接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现。如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的值存入接口类型的值。
接口的零值是nil
接口
一个接口类型定义了一套方法,如果一个具体类型要实现该接口,那么必须实现该接口类型中的所有方法
结构体赋值给接口:
如果一个struct实现了interface中的所有方法,那么可以将一个struct的变量赋值给一个interface,只实现一部分方法,那么就不能赋值操作。
这个例子中,如果notifier中还有一个demo()方法,但是person没有实现这个demo(),那么在主函数中执行赋值就会出错,提示没有实现notifier的所有接口
方法集
方法集定义了一组关联到给定类型的值或者指针的方法。定义方法时使用的接收者的类型决定了这个方法是关联到值,还是关联到指针,还是两个都关联:
Values | Methods Receivers |
---|---|
T | (t T) |
*T | (t T) and (t *T) |
上述表格展示了规范里对方法集的描述。描述中说道,T类型的值的方法集值包含值接收者声明的方法。而指向T类型的指针的方法集即可包含值接收者声明的方法,也包含指针接收者声明的方法。
换个角度从接收者的角度来看一下这些规则:
Methods Receivers | Values |
---|---|
(t T) | t and *T |
(t *T) | *T |
上述表格说明,如果使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口
代码说明:
多态
|
|
类型断言
类型断言是一个作用在接口值上的操作,写出来类似于x.(T), 其中x是一个接口类型的表达式,而T是一个类型(称为断言类型).类型断言会检查作为操作数的动态类型是否满足指定的断言类型。
这里有两个可能:
首先检查成功,类型断言的结果就是x的动态之,类型当然就是T。换句话说,类型断言就是用来从他的操作数中把具体类型的值提取出来的操作。如果检查失败,那么操作错误:
其次,如果断言类型T是一个接口类型,那么类型断言检查x的动态类型是否满足T。如果检查成功,动态值并没有提取出来,结果仍然是一个接口值,接口值的类型和值部门也没有变更,只是结果的类型为接口类型T。
换句话说,类型断言是一个接口值表达式,从一个接口类型变为拥有另外一套方法的接口类型(通常方法数量是增多), 但保留了接口之中的动态类型和动态值部分:
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // 成功: *os.File 有 Read 和 Writer 方法
w = new(ByteCounter)
rw = w.(io.ReadWriter) // 异常: *ByteCounter 没有Read方法
无论哪种类型作为断言类型,如果操作数是一个空接口值,断言类型都失败。
小结
- 多个类型可以实现同一个接口
- 实现某个接口的类型可以有其他的方法(除了实现接口方法外)
- 一个类型可以实现多个接口
- 方法的接收者不区分值还是指针,但实现接口方法的类型区分值和指针