接口interface
1. 接口是一个或多个方法签名的集合
2. 只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示声明实现了哪个接口,这称为 Structural typing
3. 接口只有方法声明,没有实现,没有数据字段
4. 接口可以匿名嵌入其它接口,或切入到结构中去
5. 将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品到指针,既无法修改复制品的状态,也无法获取指针
6. 只有当接口存储的类型和对象都为 nil 时,接口才等于 nil
7. 接口调用不会做 receiver 的自动转换
8. 接口同样支持匿名字段方法
9. 接口也可实现类似 OOP 中的多态
10. 空接口可以作为任何类型数据的容器
那么,让我们先来看一个简单的接口应用案例:
package main import "fmt" /** 定义接口 */ type USB interface { Name() string // 定义了名为Name的方法且返回类型为String Connect() // 定义了名为Connect的方法,没有返回类型形如java中的void } /** 使用结构体(java中的class) 来实现接口中的方法 具体如何实现是通过为定义的结构体绑定方法来实现,故可以看到下面代码开始先定义一个结构体之后再为这个结构添加方法 */ type PhoneConnecter struct { // 定义内部变量 name string } func (phone PhoneConnecter) Name() string { return phone.name } func (phone PhoneConnecter) Connect() { fmt.Println("Connect:", phone.name) } func main() { /*var a USB a = PhoneConnecter{"PhoneConnecter"}*/ //以上注释代码可以简写为以下形式 a := PhoneConnecter{"PhoneConnecter"} a.Connect() //那么有人问来,那你怎么知道 a 是实现来 USB 接口呢?那么我们再定义一个Disconnect函数,参数就传入 USB 类型 Disconnect(a) /** 从结果可以看出实现接口并没有声明实现哪个接口 */ } func Disconnect(usb USB) { fmt.Println("Disconnected.") }
运行结果:
Connect: PhoneConnecter Disconnected.
类型断言
1. 通过类型断言的 ok pattern可以判断接口中的数据类型
2. 使用 type switch 则可以针对空接口进行比较全面的类型判断
接口转换
可以将拥有超集的接口转换为子集的接口
更加深入的示例:
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 /** 8 定义接口 9 */ 10 type USB interface { 11 Name() string // 定义了名为Name的方法且返回类型为String 12 Connecter // 接口嵌套,USB 接口也就拥有了 Connecter 接口中 Connect() 方法 13 } 14 15 type Connecter interface { 16 Connect() 17 } 18 19 /** 20 定义结构体 21 */ 22 type PhoneConnecter struct { 23 // 定义内部变量 24 name string 25 } 26 27 /** 28 真对结构体绑定的方法method 29 */ 30 func (phone PhoneConnecter) Name() string { 31 return phone.name 32 } 33 34 func (phone PhoneConnecter) Connect() { 35 fmt.Println("Connect:", phone.name) 36 } 37 38 func main() { 39 a := PhoneConnecter{"PhoneConnecter"} 40 a.Connect() 41 Disconnect(a) 42 DisconnectAll(a) 43 DisconnectSwitch(a) 44 45 // 演示接口类型转换 46 phone := PhoneConnecter{"PhoneConnecter"} // 声明 PhoneConnecter,其实它是实现来 USB 接口的 47 var b Connecter // 声明 Connecter 接口 48 b = Connecter(phone) // 将 USB接口的类型强制转换为 Connecter 类型。即Go语言中接口转换只能从高——>低 49 b.Connect() // 当前只能调用 Connect 方法并没有 Name 方法了,因为它已经是 Connecter 类型了,不存在 Name 方法 50 } 51 52 func Disconnect(usb USB) { 53 /** 54 这里是通过类型断言来判定当前是哪个对象调用并打印 55 类型断言格式:usb.(要判断的对象),判断传入的是否为PhoneConnecter类型 56 */ 57 if phone, ok := usb.(PhoneConnecter); ok { 58 fmt.Println("Disconnected:", phone.name) 59 return 60 } 61 fmt.Println("Unknown decive.") 62 } 63 64 /** 65 Go语言中类型定义只要符合定义的接口那么它就实现来该接口,在java语言中都有一个顶级父类叫 Object。那么在Go语言中有吗? 66 当然有的,通过接口概念可以了解到当我们定义一个空接口的时候,任何类型都会继承它。那么针对Disconnect方法我们就可以定义一种更加广泛的应用方式 67 */ 68 func DisconnectAll(usb interface{}) { 69 if phone, ok := usb.(PhoneConnecter); ok { 70 fmt.Println("DisconnectAll:", phone.name) 71 return 72 } 73 fmt.Println("Unknown decive.") 74 } 75 76 /** 77 在Go语言中可以用另外一种方式进行断言,叫:type switch 78 */ 79 func DisconnectSwitch(usb interface{}) { 80 switch v := usb.(type) { 81 case PhoneConnecter: 82 fmt.Println("DisconnectSwitch:", v.name) 83 default: 84 fmt.Println("Unknown decive.") 85 } 86 }
运行结果:
Connect: PhoneConnecter Disconnected: PhoneConnecter DisconnectAll: PhoneConnecter DisconnectSwitch: PhoneConnecter Connect: PhoneConnecter