接口interface
形式
type 接口名 interface{
方法名(...) ...
...
}
核心思想
- 只要一个结构体实现了该接口的所有方法,就认为这个结构体实现了这个方法,便可以用这个结构体去生成该接口的变量了。
type USB interface {
Name() string
Connect()
}
type PhoneConnector struct {
name string
}
func (pc PhoneConnector) Name() string {
return pc.name
}
func (pc PhoneConnector) Connect() {
fmt.Println("Connected", pc.name)
}
func main() {
var a USB
a = PhoneConnector{"PhoneConnector"}
a.Connect()
}
嵌入接口
type 接口名 interface{
方法名(...) ...
...
另一个接口名
}
type USB interface {
Name() string
Connector
}
type Connector interface {
Connect()
}
type PhoneConnector struct {
name string
}
func (pc PhoneConnector) Name() string {
return pc.name
}
func (pc PhoneConnector) Connect() {
fmt.Println("Connected", pc.name)
}
func Disconnect(usb USB) {
fmt.Println("Disconnected.")
}
func main() {
a := PhoneConnector{"PhoneConnector"}
a.Connect()
Disconnect(a)
}
类型断言
- 判断实现这个接口的变量是什么类型的,以便使用这个类型内独有的函数和变量
- 通过类型断言的ok pattern可以判断接口中的数据类型
- 使用type switch则可针对空接口进行比较全面的类型判断
func Disconnect(usb USB) {
if pc, ok := usb.(PhoneConnector); ok {
fmt.Println("Disconnected:", pc.name)
}
}
- 所有类型都实现了空接口
interface{}
func Disconnect(usb interface{}) {
switch v := usb.(type) {
case int:
...
case ...:
...
case PhoneConnector:
fmt.Println("Disconnected:", v.name)
default:
fmt.Println("Unknown device.")
}
}
接口转换
- 一个接口只能"降级"转换成它所嵌入的子接口,反之不行
a := PhoneConnector{"PhoneConnector"}
b := Connector(a)
//b.Name() //无法调用
注意事项
- 将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个
复制品的指针,既无法修改复制品的状态,也无法获取指针。
a := PhoneConnector{"PhoneConnector"}
b := Connector(a)
b.Connect()
a.name = "22222"
b.Connect()
输出结果
Connected PhoneConnector
Connected PhoneConnector
- 只有当接口存储的类型和对象都为nil时,接口才等于nil
var a interface{}
fmt.Println(a == nil)
var p *int = nil
a = p
fmt.Println(a == nil)
输出结果
true
false
- 接口调用不会做receiver的自动转换
- 接口同样支持匿名字段方法
- 接口也可实现类似OOP中的多态
- 空接口可以作为任何类型数据的容器