接口实现判断依据
- 值方法集和接口匹配
- 给接口变量赋值的不管是值还是指针对象,都ok,因为都包含值方法集
- 指针方法集和接口匹配
- 只能将指针对象赋值给接口变量,因为只有指针方法集和接口匹配
- 如果将值对象赋值给接口变量,会在编译期报错(会触发接口合理性检查机制)
接口绑定
1 | type Annimaler interface { |
基于以上的代码,我们大致可以写出 go interface 合理性验证的代码如下:
1 | var _ Annimaler = &Dog{} |
1 | var _ Annimaler = (*Dog)(nil) |
代码解释
赋值的右边应该是断言类型的零值,也就是说 Dog 类型的零值等于Annimaler类型的零值。
如果是指针类型(如 *Annimaler)、切片和映射,这是 nil;
如果是结构类型,这是空结构。
(*Dog)(nil) 是类型断言,就是把变量用
nil代替,把nil转换成一个Dog类型的空指针后赋值给Annimaler
接收器 (receiver) 与接口,接口与具体方法集的匹配
一个类型可以有值接收器方法集和指针接收器方法集
使用值接收器的方法既可以通过值调用,也可以通过指针调用。带指针接收器的方法只能通过指针或 addressable values调用(其实和值调用类似)。
如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是对象的副本,不影响调用者;如果方法的接收者是指针类型,则调用者修改的是指针指向的对象本身。
通常我们使用指针作为方法的接收者的理由:
- 使用指针方法能够修改接收者指向的值。
- 可以避免在每次调用方法时复制该值,在值的类型为大型结构体时,这样做会更加高效。
在该代码中:
1 | i = &Dog{} |
编译是可以通过的,这就是通过 addressable values 调用的。
参考资料
- uber-go/guide的中文翻译:https://github.com/xxjwxc/uber_go_guide_cn