接口的基本概念
接口是一组行为规范的集合。
type Transporter interface { //定义接口。通常接口名以er结尾
//接口里面只定义方法,不定义变量
move(src string, dest string) (int, error) //方法名 (参数列表) 返回值列表
whistle(int) int //参数列表和返回值列表里的变量名可以省略
}
只要结构体拥有接口里声明的所有方法,就称该结构体实现了接口。
一个struct可以同时实现多个接口。
type Car struct { //定义结构体时无需要显式声明它要实现什么接口
price int
}
func (car Car) move(src string, dest string) (int, error) {
return car.price, nil
}
func (car Car) whistle(n int) int {
return n
}
接口值有两部分组成, 一个指向该接口的具体类型的指针和另外一个指向该具体类型真实数据的指针。
car := Car{"宝马", 100}
var transporter Transporter
transporter = car
接口的使用
func transport(src, dest string, transporter Transporter) error {
_,err := transporter.move(src, dest)
return err
}
var car Car //Car实现了Transporter接口
var ship Shiper // Shiper实现了Transporter接口
transport("北京", "天津", car)
transport("北京", "天津", ship)
接口的赋值
如果是指针实现了方法,那只能给接口赋值指针
如果是值实现了方法,那可以给接口赋值指针,也可以赋值值
func (car Car) whistle(n int) int {…}//方法接收者是值
func (ship *Shiper) whistle(n int) int {…} //方法接收者用指针,则实现接口的是指针类型
car := Car{}
ship := Shiper{}
var transporter Transporter
transporter = car
transporter = &car //值实现的方法,指针同样也实现了
transporter = &ship
接口嵌入
将被嵌入的接口,继承嵌入接口的所有方法
type Transporter interface {
whistle(int) int
}
type Steamer interface {
Transporter //接口嵌入。相当于Transporter接口定义的行为集合是Steamer的子集
displacement() int
}
空接口
空接口类型用interface{}
表示,注意有{}
。
var i interface{}
在go中any
也是空接口
源码
type any = interface{}
空接口没有定义任何方法,因此任意类型都实现了空接口。
var a int = 5
i = a
func square(x interface{}){} //该函数可以接收任意数据类型
slice的元素、map的key和value都可以是空接口类型。
map中的key可以是任意能够用==
操作符比较的类型,不能是函数、map、切片,以及包含上述3中类型成员变量的的struct。
map的value可以是任意类型。
类型断言
if v, ok := i.(int); ok {//若断言成功,则ok为true,v是具体的类型 如果断言失败,v就是个空的
fmt.Printf("i是int类型,其值为%d\n", v)
}else if v, ok := i.(string); ok{
fmt.Printf("i是string类型,其值为%s\n", v)
}else {
fmt.Println("i不是int和string类型")
}
当要判断的类型比较多时,就需要写很多if-else
,更好的方法是使用switch i.(type)
。
switch v := i.(type) { //隐式地在每个case中声明了一个变量v
case int: //v已被转为int类型
fmt.Printf("ele is int, value is %d\n", v)
//在 Type Switch 语句的 case 子句中不能使用fallthrough
case float64: //v已被转为float64类型
fmt.Printf("ele is float64, value is %f\n", v)
case int8, int32, byte: //如果case后面跟多种type,则v还是interface{}类型
fmt.Printf("ele is %T, value is %d\n", v, v)
}
面向接口编程
电商推荐流程
为每一个步骤定义一个接口。
type Recaller interface {
Recall(n int) []*common.Product //生成一批推荐候选集
}
type Sorter interface {
Sort([]*common.Product) []*common.Product //传入一批商品,返回排序之后的商品
}
type Filter interface {
Filter([]*common.Product) []*common.Product //传入一批商品,返回过滤之后的商品
}
type Recommender struct {
Recallers []recall.Recaller
Sorter sort.Sorter
Filters []filter.Filter
}
使用纯接口编写推荐主流程。
func (rec *Recommender) Rec() []*common.Product {
RecallMap := make(map[int]*common.Product, 100)
//顺序执行多路召回
for _, recaller := range rec.Recallers {
products := recaller.Recall(10) //统一设置每路最多召回10个商品
for _, product := range products {
RecallMap[product.Id] = product //把多路召回的结果放到map里,按Id进行排重
}
}
//把map转成slice
RecallSlice := make([]*common.Product, 0, len(RecallMap))
for _, product := range RecallMap {
RecallSlice = append(RecallSlice, product)
}
SortedResult := rec.Sorter.Sort(RecallSlice) //对召回的结果进行排序
//顺序执行多种过滤规则
FilteredResult := SortedResult
for _, filter := range rec.Filters {
FilteredResult = filter.Filter(FilteredResult)
}
return FilteredResult
}
面向接口编程,在框架层面全是接口。
具体的实现由不同的开发者去完成,每种实现单独放到一个go文件里,大家的代码互不干扰。
通过配置选择采用哪种实现,也方便进行效果对比。
校验是否实现接口
定义接口
// user模块中定义的接口
type Server interface {
DeleteUser(ctx context.Context, in *DeleteUserRequest) (*User, error)
}
实现接口
type implServer struct {
}
校验接口
var _ user.Server = (*implServer)(nil)
这么做的目的是让IDE能够提示咱们,是否实现了对应的接口,非常方便
标签:int,car,编程,接口,interface,GO,Transporter,type From: https://www.cnblogs.com/guangdelw/p/17766762.html