接口不包含成员变量

Go 语言中的两种接口

Go 语言使用 runtime.iface 表示第一种接口,使用 runtime.eface 表示第二种不包含任何方法的接口 interface{},两种接口虽然都使用 interface 声明,但是由于后者在 Go 语言中很常见,所以在实现时使用了特殊的类型

结构体和指针实现接口

虽然两种类型不同,但是上图中的两种实现不可以同时存在,Go 语言的编译器会在结构体类型和指针类型都实现一个方法时报错 “method redeclared”。

type Duck interface { Quack() }

type Cat struct{}

func (c *Cat) Quack() { fmt.Println(“meow”) }

func main() { var c Duck = Cat{} c.Quack() }

$ go build interface.go ./interface.go:20:6: cannot use Cat literal (type Cat) as type Duck in assignment: Cat does not implement Duck (Quack method has pointer receiver)

原因在于参数传递时,go是传值的,发生拷贝后,指针指向发生变化

通过一个例子理解Go 语言的接口类型不是任意类型这一句话

interface的nil 和 类型变量的nil的区别

前者要求类型和值都为nil

runtime._type 是 Go 语言类型的运行时表示。下面是运行时包中的结构体,其中包含了很多类型的元信息,例如:类型的大小、哈希、对齐以及种类等。

runtime.itab 结构体是接口类型的核心组成部分,每一个 runtime.itab 都占 32 字节,我们可以将其看成接口类型和具体类型的组合,

动态派发 如果编译期间不能确认接口的类型,Go 语言会在运行期间决定具体调用该方法的哪个实现。

从上述表格我们可以看到使用结构体实现接口带来的开销会大于使用指针实现,而动态派发在结构体上的表现非常差,这也提醒我们应当尽量避免使用结构体类型实现接口。