文章目录
接口(interface)
基本介绍
基本介绍
- 在Go中,接口(interface)是一种用于定义方法集合的抽象类型,接口中定义了一组方法的签名,而不包含方法的实现细节,其他类型可以通过实现接口中定义的方法来满足接口的要求。
- 接口的实现是隐式的,类型不需要显式声明它实现了某个接口,只要类型提供了接口中定义的所有方法,就被视为实现了该接口。
- 接口提供了一种灵活的方式来定义和使用抽象的行为,通过接口可以实现与类型无关的编程,提高代码的灵活性和可扩展性。
接口的定义方式
接口的定义方式
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)
}
代码解释:
- 在现实生活中,手机和相机都可以通过USB接口与电脑传输数据,因此将Computer的Working方法的参数设置为Usb接口类型,此时Working方法就能接收任何实现了Usb接口的自定义类型变量。
- 由于Phone和Camera都实现了Usb接口,因此在调用Computer的Working方法时,如果传入的是Phone类型的变量,那么在Working方法内部调用的就是Phone对应的Start和Stop方法,如果传入的是Camera类型的变量,则调用的是Camera的Start和Stop方法。
程序的运行结果如下:
注意: 类型在实现接口中的定义的方法时,要么全部使用值接收者绑定,要么全部使用指针接收者绑定,不能在一个类型上混合使用值接收者和指针接收者来实现同一个接口。
接口的大小
接口类型本质是包含两个指针字段的数据结构:
- 动态类型指针:该指针指向接口变量所持有的数据值的类型信息,可以用于在运行时进行类型断言和动态方法调用。如果接口变量为空(nil),则动态类型指针也为空(nil)。
- 动态值指针:该指针指向接口变量所持有的数据值,具体的类型由动态类型指针指示。如果接口变量为空(nil),那么动态值指针也为空(nil)。
示意图如下:
因此对于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