之前在学C++的时候,指针的用法就困惑了很久。后来有了计算机体系结构基础后,再加上Golang的一些说明,就突然明白了,之前纠结的点在哪里。
其实让我明白的只是因为Go tour中的两句话:
Struct fields can be accessed through a struct pointer.
结构体字段可以使用结构体指针获取。
To access the field X of a struct when we have the struct pointer p we could write (*p).X. However, that notation is cumbersome, so the language permits us instead to write just p.X, without the explicit dereference.
结构体指针访问字段本来应该写成(*p).x,但是由于这么写太蠢了,所以允许直接写成p.x。
也就是说,如果见到类似T.x
的结构体访问,T有可能是结构体本身,也可能是指针……需要自行区分。
但有的时候会有很难区分的情况:
-
定义了一个接口Interface,方法有Intera(),Interb()
type Interface interface{ Intera() Interb() }
-
定义了一个结构体Base,用结构体指针的方式实现了Intera()
type Base struct {} func (b *Base) Intera() {}
-
定义了一个结构体Extend,匿名组合了Base,用正常结构体的方式实现了Interb()
type Extend struct { Base } func (e Extend) Interb() {}
这个时候,请问谁实现了Interface?
答案是Base和Extend本身都没有实现Interface。
但是上述代码中完全没有出现的*Extend(Extend的指针)实现了Interface。
为什么呢?虽然*Extend并没有实现第二个方法,但Extend实现了,所以*Extend是也是可以直接访问第二个方法的(参考上面的(*p).x的解释)。
而*Base实现了第一个方法(Base没有实现),而Extend组合了Base。因此第一个方法可以也通过*Extend访问(Extend无法访问)。
所以*Extend两个方法都能访问,因此实现了Interface。而Extend只能访问第二个方法,因此没有实现Interface。
然后日常使用Extend的时候,为了能使用Interface的方法,会这么写:
interfacelist := make([]Interface, 0)
interfacelist = append(interfacelist, &Extend{}) // 因为是指针实现Interface,需要传入地址
e = interfacelist[0]
在goland对e按下F1时,只会显示,这是个Interface,不会告诉你这是*Extend。如果不是自己从头写的代码,你可能很久都无法发现,这个Interface的实现其实是个指针。你必须在层层组合中,找到是哪一层(这里是Base)让Extend变成了Interface的指针实现。
对e的type assertion也应该这么写:
e_ptr = e.(*Extend) // 从Interface类型返回一个Extend类型的指针
e_ptr.Base // 等于(*e_ptr).Base
有疑问加站长微信联系(非本文作者)