这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
接口在Go语言有着至关重要的地位。如果说goroutine和channel 是支撑起Go语言的并发模型 的基石,让Go语言在如今集群化与多核化的时代成为一道极为亮丽的风景,那么接口是Go语言 整个类型系统的基石,让Go语言在基础编程哲学的探索上达到前所未有的高度。
Java的接口
interface IFoo {
void Bar();
}
class Foo implements IFoo { // Java文法
// ...
}
这种接口(包括C++的)与其接口实现类的对应关系是由包路径和声明(implements) 决定的, 我们称之为"侵入式接口"
非侵入式接口
在Go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口
非侵入式接口的优点:
其一,Go语言的标准库,再也不需要绘制类库的继承树图
其二,实现类的时候,只需要关心自己应该提供哪些方法,不用再纠结接口需要拆得多细才合理。接口由使用方按需定义,而不用事前规划。
其三,不用为了实现一个接口而导入一个包,因为多引用一个外部的包,就意味着更多的耦合。接口由使用方按自身需求来定义,使用方无需关心是否有其他模块定义过类似的接口。
接口语法
接口赋值
- 将对象实例赋值给接口:
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Integer) Add(b Integer) {
*a += b
}
type LessAdd interface {
Less(b Integer) bool
Add(b Integer)
}
如果定义如上方法和接口, 然后将Integer实例赋值给LessAdd接口: 则必须用&取地址后赋值, 我的理解是必须拿到a的地址, 才可以用Add方法去修改a的值, 否则Integer未实现接口的Add方法
对于这个问题, 该某乎答主的解释是: 在类型的接收者不包含指针类型时, 可以使用a或者&a, 使用&a时编译器进行解引用
如何理解Golang中的接口? - 知乎 (zhihu.com)
var a Integer = 1
var i LessAdd = a //编译器报错
var i LessAdd = &a
- 接口间赋值
AB接口存在子集关系, 则大的可以赋值给小的(不影响调用小的方法)
接口查询
- 查询接口是否实现了另一个接口:
var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
//...
}
- 接口指向的对象是否是某个类型
var file1 Writer = ...
if file6, ok := file1.(*File); ok {
//...
}
- 类型查询, 用xx.(type)即可获得对象类型
var v1 interface{} = ...
switch v := v1.(type) {
case int: // 现在v的类型是int
case string: // 现在v的类型是string
...
}