wisecsj / wisecsj.github.io

Blog
Apache License 2.0
0 stars 0 forks source link

Golang:Struct and interface(Embedded) #18

Open wisecsj opened 5 years ago

wisecsj commented 5 years ago

结构体与接口的内嵌,有四种情况

wisecsj commented 5 years ago

1.接口嵌套接口

相当于是外层接口也定义了内层接口的方法

2.接口内嵌结构体

直接编译报错

3.结构体内嵌接口

相当于结构体具有了接口的method,初始化时接口字段需要用实现了此接口的类型赋值。

外层结构体也可以作为receiver,定义与接口内部同名的方法,从而实现覆盖。

4.结构体内嵌结构体

外层结构体自动获得内层结构体的字段和方法,同3,也可以进行覆盖

wisecsj commented 5 years ago

对于结构体A,它有实例a(类型为A),和b(类型为A),和方法funca(接收器类型为A),funcb(接收器类型为A),则有:

无论是a还是b,都可以调用方法funca和funcb,因为GO会自动隐式地帮你转换成正确的类型
虽然都可以进行调用,但是值变量只拥有值方法集,指针变量则同时拥有值方法集和指针方法集
当需要改变结构体数据时,用指针方法,不需要时,用值方法

但是对于接口变量上的指针方法与值方法:

规则一:如果使用指针方法来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。
规则二:如果使用值方法来实现一个接口,那么那个类型的值和指针都能够实现对应的接口。

按照上面的两条规则,那究竟怎么选择是指针接收器还是值接收器呢?

何时使用值类型

(1)如果接收器是一个 map,func 或者 chan,使用值类型(因为它们本身就是引用类型)。

(2)如果接收器是一个 slice,并且方法不执行 reslice 操作,也不重新分配内存给 slice,使用值类型。

(3)如果接收器是一个小的数组或者原生的值类型结构体类型(比如 time.Time 类型),而且没有可修改的字段和指针,又或者接收器是一个简单地基本类型像是 int 和 string,使用值类型就好了。

值类型的接收器可以减少一定数量的内存垃圾生成,值类型接收器一般会在栈上分配到内存(但也不一定),在没搞明白代码想干什么之前,别为这个原因而选择值类型接收器。

何时使用指针类型

(1)如果方法需要修改接收器里的数据,则接收器必须是指针类型。

(2)如果接收器是一个包含了 sync.Mutex 或者类似同步字段的结构体,接收器必须是指针,这样可以避免拷贝。

(3)如果接收器是一个大的结构体或者数组,那么指针类型接收器更有效率。

(4)如果接收器是一个结构体,数组或者 slice,它们中任意一个元素是指针类型而且可能被修改,建议使用指针类型接收器,这样会增加程序的可读性。

最后如果实在还是不知道该使用哪种接收器,那么记住使用指针接收器是最靠谱的。

内嵌结构体的方法提升规则:

规则一:如果S包含嵌入字段T,则S和S的方法集都包括具有接收方T的提升方法。S的方法集还包括具有接收方*T的提升方法。

规则二:如果S包含嵌入字段T,则S和S的方法集都包括具有接收器T或*T的提升方法。