关于Golang的结构体与指针不得不提的二三事

三水L · · 772 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:三水L

查看原文:关于Golang的结构体与指针不得不提的二三事

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

772 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传