之前在学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

但有的时候会有很难区分的情况:

type Interface interface{
  Intera()
  Interb()
}
type Base struct {}
func (b *Base) Intera() {}
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