Go中的接口是一个方法集合,类型必须实现这些方法才能符合该接口。没有显式的关键字implements:兼容性是_结构性的_,而不是声明性的。只有当类型实现了接口的所有方法时,才能将实现类型赋值给接口类型的变量。
重要的是:接口变量包含两个指针——一个指向数据(value),一个指向类型(type)。
示例声明和实现:
type Printer interface { Print() } type MyPrinter struct{} func (mp MyPrinter) Print() { fmt.Println("printing...") } var p Printer = MyPrinter{} p.Print() // "printing..."
如果接口变量为nil,会发生什么?"var i interface{} = nil"与"var i interface{}"有什么区别?
一个常见的错误答案是"两个值都是nil"。实际上——不是:
var i interface{} = nil——变量确实为nil(type=nil,value=nil)var p *MyPrinter = nil; var i Printer = p,那么i != nil,因为type != nil(在i内部——type=*MyPrinter,value=nil),许多诸如if i == nil的检查不会按预期工作。示例:
var p *MyPrinter = nil var i Printer = p fmt.Println(i == nil) // false!
故事
描述: 在一个服务中,错误处理程序返回了一个带nil值的接口,客户端将其视为非空错误,导致多余的操作。问题在于接口与nil的比较。
故事
描述: 在编写测试时,错误地检查了接口类型的错误是否等于nil,之后返回了具有nil字段的结构。测试未检测到真正的错误,导致生产中的bug出现。
故事
描述: 在从一个接口类型迁移到另一个接口类型时,忘记实现新接口的所有方法,因为没有显式的implements。代码编译通过,但接口未实现,一些模拟函数停止工作。