在b站看到各食品讲解go的interface,引发我的兴趣007-go语言中的interface(上)原理

其中给出了一个模型来解释go的interface在内存上的形状,这样也许能更好理解一些

1
2
3
4
5
6
7
8
9
package main

import "fmt"
import "unsafe"

type interface_struct struct {
Type unsafe.Pointer
Data unsafe.Pointer
}

特性理解

go的interface有点像cpp的抽象类里面的虚函数,但是又由于go本身的特性,导致其和cpp还是有一些区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import "fmt"

type Speaker interface {
Speak() string
}

type Dog struct {}
type Person struct {}

func (d Dog) Speak() string {
return "汪汪!"
}

func (p Person) Speak() string {
return "你好!"
}

func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}

func main() {
var s0 Speaker = &Person{}
var s1 Speaker = (*Person)(nil)
var s2 Speaker = nil

fmt.Println(s0 == nil)
fmt.Println(s0.Speak())

fmt.Println(s1 == nil)
fmt.Println(s1.Speak())

fmt.Println(s2 == nil)
// fmt.Println(s2.Speak())
}

示例的结果类似于

1
2
3
4
5
6
7
8
9
10
false
你好!
false
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4982df]

goroutine 1 [running]:
main.main()
/home/dbgbgtf/Main/work/test_go/main.go:33 +0xbf
exit status 2

可以看到s0s1都被认为不是nil。但是在调用方法时,s0可以,s1却失败了
这里可以用cpp的理解来说,s0s1都是Person类型的指针,但是由于s1是空指针,无法真正调用Speaker()

s1s2的区别则在于类型,可以看到这里和cpp不一样。在赋值时,*Person的这个类型就应该被赋给s1
所以在检查s1 == nil时,会返回一个false。因为s1的类型为*Person
s2则是一个空类型空指针,所以在检查s2 == nil时,返回了true

实际使用?

我刚刚开始学go,还没写过什么go项目,所以只是猜测下
这个东西应该类似于cpp的抽象类,只不过他不能带上变量,而只能储存方法
可以比较好的抽象一些类似的结构体方法于一个类型