赞
踩
基本介绍
接口的定义方式
Go中接口的定义方式如下:
相关说明:
例如,下面的代码中定义了一个Usb接口,并让自定义类型Phone和Camera实现了该接口。如下:
package main import "fmt" // 定义接口 type Usb interface { Start() Stop() } type Phone struct{} // Phone实现Usb接口的所有方法 func (p Phone) Start() { fmt.Println("phone start working...") } func (p Phone) Stop() { fmt.Println("phone stop working...") } type Camera struct{} // Camera实现Usb接口的所有方法 func (c Camera) Start() { fmt.Println("camera start working...") } func (c Camera) Stop() { fmt.Println("camera stop working...") } type Computer struct{} func (c Computer) Working(usb Usb) { // 参数是Usb接口类型,可以接收任何实现了Usb接口的类型变量 usb.Start() usb.Stop() } func main() { computer := Computer{} phone := Phone{} camera := Camera{} computer.Working(phone) computer.Working(camera) }
代码解释:
程序的运行结果如下:
注意: 类型在实现接口中的定义的方法时,要么全部使用值接收者绑定,要么全部使用指针接收者绑定,不能在一个类型上混合使用值接收者和指针接收者来实现同一个接口。
接口的大小
接口类型本质是包含两个指针字段的数据结构:
示意图如下:
因此对于64位系统来说,接口类型变量的大小为固定的16字节,其中8个字节用于存储动态类型指针,另外8个字节用于存储动态值指针。如下:
package main import ( "fmt" "unsafe" ) type Usb interface { Start() Stop() } func main() { var usb Usb fmt.Printf("usb value = %v\n", usb) // usb value = <nil> fmt.Printf("usb type = %T\n", usb) // usb type = <nil> fmt.Printf("usb size = %d\n", unsafe.Sizeof(usb)) // usb size = 16 }
接口继承
在定义接口时,一个接口可以继承多个其他接口,此时如果一个自定义类型要实现该接口,除了需要实现该接口中定义的方法外,还需要实现该接口继承的其他接口中定义的方法。如下:
package main import "fmt" type AInterface interface { test1() } type BInterface interface { test2() } type CInterface interface { AInterface // 继承接口A BInterface // 继承接口B test3() } type Student struct{} // Student实现A接口及其继承的B接口和C接口的所有方法 func (stu Student) test1() { fmt.Println("test1...") } func (stu Student) test2() { fmt.Println("test2...") } func (stu Student) test3() { fmt.Println("test3...") } func main() { var c CInterface = Student{} c.test1() // test1... c.test2() // test2... c.test3() // test3... }
注意: 只有实现了接口的类型,才能将其实例赋值给相应接口类型的变量,否则会产生报错。
空接口
空接口interface{}中没有定义任何方法,因此所有的类型都实现了空接口,可以将任意类型的变量赋值给空接口。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } func PrintValue(value interface{}) { // 参数是空接口类型,可以接收任意类型变量 fmt.Printf("value = %v\n", value) } func main() { PrintValue(10) // value = 10 PrintValue(true) // value = true PrintValue(Student{"Alice", 12, "女"}) // value = {Alice 12 女} PrintValue(1.2) // value = 1.2 PrintValue("Hello World") // value = Hello World }
自定义类型排序
Go标准库的sort包中提供了Sort函数,可用于对自定义类型序列进行排序。该函数的签名如下:
func Sort(data Interface)
Sort函数接收一个Interface类型的参数,并对其进行原地排序。Interface在sort包中是一个接口类型,接口中定义了三个方法,因此要使用Sort函数进行排序,需要先让自定义类型序列实现Interface接口。Interface接口的定义如下:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
相关说明:
使用案例如下:
package main import ( "fmt" "sort" ) type Student struct { Name string Score float64 } type Students []Student // Students实现sort.Interface接口的所有方法 func (stus Students) Len() int { return len(stus) } func (stus Students) Less(i int, j int) bool { return stus[i].Score < stus[j].Score } func (stus Students) Swap(i int, j int) { stus[i], stus[j] = stus[j], stus[i] } func main() { var stus = Students{ {"张三", 89}, {"李四", 67}, {"王五", 75}, {"赵六", 99}, {"田七", 58}, {"周八", 92}, } fmt.Printf("stus = %v\n", stus) // stus = [{张三 89} {李四 67} {王五 75} {赵六 99} {田七 58} {周八 92}] sort.Sort(stus) fmt.Printf("stus = %v\n", stus) // stus = [{田七 58} {李四 67} {王五 75} {张三 89} {周八 92} {赵六 99}] }
说明一下:
i, j = j, i
是一种特殊的赋值写法,可以避免在交换两个变量的值时使用额外的临时变量。接口与继承
接口与继承的关系如下:
此外,接口可以看作是对继承的一种补充,当某个结构体需要扩展功能,同时不希望破坏已有的继承关系,这时可以定义出一个接口对其进行实现。如下:
上图说明:
基本介绍
多态的实现
基本介绍
不带检测的类型断言
通过接口变量.(类型)
的方式可以将接口变量转换为指定类型,如果接口变量底层是所指定的类型,则断言成功并返回类型转换后的值,否则断言失败并触发panic异常。如下:
package main
import "fmt"
func TypeAssert(value interface{}) {
num := value.(int) // 不带检测的类型断言
fmt.Printf("num = %d\n", num)
}
func main() {
TypeAssert(10) // num = 10
// TypeAssert(10.1) // 类型断言失败,抛出panic
}
带检测的类型断言
当类型断言失败时如果不希望触发panic异常,可以对接口变量.(类型)
的第二个返回值进行接收,其表示本次类型断言是否成功,如果类型断言成功,则第一个返回值是类型转换后的值,如果类型断言失败,则第一个返回值是所指定类型的零值。如下:
package main import "fmt" type Usb interface { Start() Stop() } type Phone struct{} // Phone实现Usb接口的所有方法 func (p Phone) Start() { fmt.Println("phone start working...") } func (p Phone) Stop() { fmt.Println("phone stop working...") } func (p Phone) Prompt() { fmt.Println("phone get a prompt information...") } type Camera struct{} // Camera实现Usb接口的所有方法 func (c Camera) Start() { fmt.Println("camera start working...") } func (c Camera) Stop() { fmt.Println("camera stop working...") } type Computer struct{} func (c Computer) Working(usb Usb) { // 参数是Usb接口类型,可以接收任何实现了Usb接口的类型变量 usb.Start() if phone, ok := usb.(Phone); ok { // 带检测的类型断言 phone.Prompt() } usb.Stop() } func main() { computer := Computer{} phone := Phone{} camera := Camera{} computer.Working(phone) computer.Working(camera) }
上述代码在Working方法中通过类型断言对Phone类型进行了特殊处理,运行程序后可以看到,在调用Computer的Working方法时,如果传入的是Phone类型变量,除了会调用其Start和Stop方法外,还会调用Phone的Prompt方法。如下:
参数类型识别
将类型断言与switch语句相结合(Type Switch),可以将接口变量转换为具体类型,并根据不同的类型指向相应的代码逻辑。如下:
package main import "fmt" type Student struct { Name string Age int Gender string } func TypeJudge(values ...interface{}) { // 参数是空接口类型的可变参数,可以接收任意个数的任意类型参数 for i := 0; i < len(values); i++ { switch values[i].(type) { case int: fmt.Printf("第%d个参数: value = %v, type = int\n", i+1, values[i]) case float64: fmt.Printf("第%d个参数: value = %v, type = float64\n", i+1, values[i]) case bool: fmt.Printf("第%d个参数: value = %v, type = bool\n", i+1, values[i]) case Student: fmt.Printf("第%d个参数: value = %v, type = Student\n", i+1, values[i]) case *Student: fmt.Printf("第%d个参数: value = %v, type = *Student\n", i+1, values[i]) default: fmt.Printf("第%d个参数: value = %v, type unknown\n", i+1, values[i]) } } } func main() { var stu = Student{"Alice", 12, "女"} TypeJudge(10, 12.2, true, stu, &stu, "Hello World") }
程序运行结果如下:
接口断言
通过接口变量.(接口类型)
的方式,可以判断接口变量底层指向的类型是否实现了所指定的接口类型。如下:
package main import "fmt" type Usb interface { Start() Stop() } type Phone struct{} // Phone实现Usb接口的所有方法 func (p Phone) Start() { fmt.Println("phone start working...") } func (p Phone) Stop() { fmt.Println("phone stop working...") } type Camera struct{} // Camera只实现Usb接口的Start方法 func (c Camera) Start() { fmt.Println("camera start working...") } func InterfaceAssert(value interface{}) { if _, ok := value.(Usb); ok { // 接口断言 fmt.Printf("%T implemented the Usb interface...\n", value) } else { fmt.Printf("%T does not implemented the Usb interface...\n", value) } } func main() { phone := Phone{} camera := Camera{} InterfaceAssert(phone) // main.Phone implemented the Usb interface... InterfaceAssert(camera) // main.Camera does not implemented the Usb interface... }
注意:
具体类型变量.(接口类型)
的方式判断某个类型是否实现了所指定的接口类型,这时应该通过interface{}(具体类型变量).(接口类型)
的方式先将具体类型变量转换为空接口类型,然后再进行接口断言。接口变量.(接口类型)
的第二个返回值表示本次接口断言是否成功,如果接口断言成功,则第一个返回值是转换为指定接口类型后的值,如果接口断言失败,则第一个值是所指定接口类型的零值,如果不对第二个返回值进行接收,那么断言失败时会触发panic异常。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。