一、Golang 接口
Golang 中接口定义了对象的行为规范,只定义规范不实现。接口中定义的规范由具体的对象来实现。
package main import ( "fmt" ) //接口是一个规范 type Usber interface { // 最好以 er 结尾表示接口 start() stop() } // 如果接口里有方法的话,必须要通过结构体或者通过自定义类型实现这个接口。 type Phone struct { Name string } // 手机要实现 usb 接口的话必须得实现 usb 接口中的所有方法 func (p Phone) start() { fmt.Println(p.Name, "启动") } func (p Phone) stop() { fmt.Println(p.Name, "关机") } func main() { p := Phone{ Name: "华为手机", } p.start() var p1 Usber // Golang 中接口就是一个数据类型 p1 = p // 表示手机实现 Usb 接口 p1.start() p1.stop() }
输出:
华为手机 启动 华为手机 启动 华为手机 关机
空接口
空接口表示没有任何约束,因此任何类型变量都可以实现空接口。
package main import ( "fmt" ) // Golang 中空接口也可以直接当作类型来使用,可以表示任意类型 func main() { var a interface{} // 空接口可以接收任意类型 a = 20 fmt.Printf("值: %v 类型:%T\n", a, a) a = "你好golang" fmt.Printf("值: %v 类型:%T\n", a, a) a = true fmt.Printf("值: %v 类型:%T\n", a, a) }
输出:
值: 20 类型:int 值: 你好golang 类型:string 值: true 类型:bool
1. 空接口可以作为函数的参数
package main import ( "fmt" ) // 1、空接口可以作为函数的参数 func show(a interface{}) { fmt.Printf("值:%v 类型:%T\n", a, a) } // Golang 中空接口也可以直接当作类型来使用,可以表示任意类型 func main() { show(20) show("你好golang") slice := []int{1, 2, 3, 4} show(slice) }
输出:
值:20 类型:int 值:你好golang 类型:string 值:[1 2 3 4] 类型:[]int
2. map 的值实现空接口
package main import ( "fmt" ) // 2、map 的值实现空接口 func show(a interface{}) { fmt.Printf("值:%v 类型:%T\n", a, a) } func main() { var m1 = make(map[string]interface{}) m1["username"] = "张三" m1["age"] = 20 m1["married"] = true fmt.Println(m1) var s1 = []interface{}{1, 2, "你好", true} fmt.Println(s1) }
输出:
map[age:20 married:true username:张三] [1 2 你好 true]
类型断言
package main import ( "fmt" ) func main() { var a interface{} a = "你好golang" v, ok := a.(string) if ok { fmt.Println("a就是一个string类型,值是:", v) } else { fmt.Println("断言失败") } }
输出:
a就是一个string类型,值是: 你好golang
另一种写法:
package main import ( "fmt" ) // 1、X.(T) 括号里表示 X 可能是的类型 func MyPrint1(x interface{}) { if _, ok := x.(string); ok { fmt.Println("string类型") } else if _, ok := x.(int); ok { fmt.Println("int类型") } else if _, ok := x.(bool); ok { fmt.Println("bool类型") } } // 2、类型.(type)只能结合 switch 语句使用 func MyPrint2(x interface{}) { switch x.(type) { case int: fmt.Println("int类型") case string: fmt.Println("string类型") case bool: fmt.Println("bool类型") default: fmt.Println("传入错误...") } } func main() { MyPrint1("你好golang") MyPrint1(true) MyPrint1(20) MyPrint2(true) MyPrint2(20) MyPrint2("你好golang") }
输出:
string类型 bool类型 int类型 bool类型 int类型 string类型
二、结构体值接收者实现接口
值接收者:如果结构体中的方法是值接收者,那么实例化后的结构体值类型和结构体指针类型都可以赋值给接口类型变量。
package main import ( "fmt" ) // 接口是一个规范 type Usber interface { // 最好以 er 结尾表示接口 start() stop() } // 如果接口里有方法的话,必须要通过结构体或者通过自定义类型实现这个接口。 type Phone struct { Name string } // 手机要实现 usb 接口的话必须得实现 usb 接口中的所有方法 func (p Phone) start() { fmt.Println(p.Name, "启动") } func (p Phone) stop() { fmt.Println(p.Name, "关机") } func main() { // 结构体值接收者实例化后的结构体值类型和结构体指针类型都可以赋值给接口变量 var p1 = Phone{ Name: "小米手机", } var p2 Usber = p1 // 表示让 Phone 实现 Usb 的接口 p2.start() var p3 = &Phone{ Name: "苹果手机", } var p4 Usber = p3 p4.start() }
输出:
小米手机 启动 苹果手机 启动
指针类型
package main import ( "fmt" ) // 接口是一个规范 type Usber interface { // 最好以 er 结尾表示接口 start() stop() } // 如果接口里有方法的话,必须要通过结构体或者通过自定义类型实现这个接口。 type Phone struct { Name string } // 手机要实现 usb 接口的话必须得实现 usb 接口中的所有方法 func (p *Phone) start() { // 指针接收者 fmt.Println(p.Name, "启动") } func (p *Phone) stop() { fmt.Println(p.Name, "关机") } func main() { /* // 错误写法 var phone1 = Phone{ Name: "小米手机", } var p1 Usber = phone1 // 表示让 Phone 实现 Usb 的接口 p1.start() */ var phone1 = &Phone{ Name: "小米", } var p1 Usber = phone1 p1.start() }
输出:
小米 启动
结构体值接收者和指针接收者实现接口的区别
值接收者:如果结构体中的方法是值接收者,那么实例化后结构体值类型和结构体指针类型都可以赋值给接口变量。
指针接收者:如果结构体中的方法是指针接收者,那么实例化后结构体指针类型都可以赋值给接口变量,结构体值类型没法赋值给接口变量。
package main import ( "fmt" ) type Animaler interface { SetName(string) GetName() string } type Dog struct { Name string } func (d *Dog) SetName(name string) { d.Name = name } func (d Dog) GetName() string { return d.Name } type Cat struct { Name string } func (c *Cat) SetName(name string) { c.Name = name } func (c Cat) GetName() string { return c.Name } func main() { // Dog 实现 Animal 的接口 d := &Dog{ Name: "小黑", } var d1 Animaler = d fmt.Println(d1.GetName()) d1.SetName("小黄") fmt.Println(d1.GetName()) // Cat 实现 Animal 的接口 c := &Cat{ Name: "小花", } var c1 Animaler = c fmt.Println(c1.GetName()) }
输出:
小黑 小黄 小花
接口嵌套
package main import ( "fmt" ) type Ainterface interface { SetName(string) } type Binterface interface { GetName() string } type Animaler interface { // 接口的嵌套 Ainterface Binterface } type Dog struct { Name string } func (d *Dog) SetName(name string) { d.Name = name } func (d Dog) GetName() string { return d.Name } func main() { d := &Dog{ Name: "小黑", } var d1 Animaler = d d1.SetName("小花") fmt.Println(d1.GetName()) }
输出:
小花
三、Golang 中空接口和类型断言使用细节
package main import ( "fmt" ) type Address struct { Name string Phone int } // Golang中空接口和类型断言使用细节 func main() { var userinfo = make(map[string]interface{}) userinfo["username"] = "张三" userinfo["age"] = 20 userinfo["hobby"] = []string{"睡觉", "吃饭"} fmt.Println(userinfo["age"]) // 20 fmt.Println(userinfo["hobby"]) // [睡觉 吃饭] var address = Address { Name: "李四", Phone: 123456, } fmt.Println(address.Name) // 李四 userinfo["address"] = address fmt.Println(userinfo["address"]) // {李四 123456} hobby2, _ := userinfo["hobby"].([]string) // 类型断言 fmt.Println(hobby2[1]) // 吃饭 address2, _ := userinfo["address"].(Address) // 类型断言 fmt.Println(address2.Name, address2.Phone) // 李四 123456 }
输出:
20 [睡觉 吃饭] 李四 {李四 123456} 吃饭 李四 123456