V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
gramyang
V2EX  ›  Go 编程语言

一个和 go 断言有关的神奇写法

  •  1
     
  •   gramyang · 2019-05-28 19:01:43 +08:00 · 3581 次点击
    这是一个创建于 1991 天前的主题,其中的信息可能已经有所发展或是发生改变。

    self := &tcpSession{ conn: conn, endNotify: endNotify, sendQueue: cellnet.NewPipe(), pInterface: p, CoreProcBundle: p.(interface { GetBundle() *peer.CoreProcBundle }).GetBundle(), }

    这是 cellnet 源码里的一段,位置是 cellnet/peer/tcp/session.go 里的 newSession。 p 是一个接口,其实现类 tcpSession 里面有一个内嵌结构体就是 peer.CoreProcBundle,peer.CoreProcBundle 有一个方法 GetBundle()。 这段代码看起来像是 p 接口断言,但是匿名接口里的方法只是 p 的子类的一个内嵌结构体的方法而已啊。。

    搞不懂,求高手指导

    第 1 条附言  ·  2019-05-28 20:08:43 +08:00
    现在我只能这么理解:
    假如一个结构体 a 和其他的结构体共同实现了一个接口 p,那么这个接口是不能准确的指代这个结构体的。

    而这个结构体 a 有自己的方法 function1,那么 p.(interface {function1})可以转型为 a,即这个 interface {function1}的匿名接口可以指代 a。
    13 条回复    2019-05-29 09:13:13 +08:00
    whoami9894
        1
    whoami9894  
       2019-05-28 19:24:34 +08:00
    tcpSession 是 interface p 的实现类 && tcpSession 内嵌了匿名 peer.CoreProcBundle
    => tcpSession 有 GetBundle 方法
    => interface p 有 GetBundle 方法
    => p 断言这个字面量类型会成功`interface { GetBundle() *peer.CoreProcBundle }`
    whoami9894
        2
    whoami9894  
       2019-05-28 19:26:36 +08:00
    @whoami9894
    通过断言转换到`interface { GetBundle() *peer.CoreProcBundle }`并调用 GetBundle
    icexin
        3
    icexin  
       2019-05-28 19:40:44 +08:00
    断言到一个匿名接口
    gramyang
        4
    gramyang  
    OP
       2019-05-28 19:57:12 +08:00
    @whoami9894。。但是 p 并没有 GetBundle 方法啊
    liulaomo
        5
    liulaomo  
       2019-05-28 20:09:17 +08:00
    @gramyang
    p 虽没有 GetBundle 方法,但是它此时的动态值有此方法即可。
    详见: https://gfw.go101.org/article/interface.html#reflection

    出现这种写法一般属于设计上没做好,但有需要一定时间才能完善的暂时之举。
    gramyang
        6
    gramyang  
    OP
       2019-05-28 20:11:19 +08:00
    @liulaomo 链接打不开啊,另外动态值怎么说来着?
    whoami9894
        7
    whoami9894  
       2019-05-28 20:22:35 +08:00 via Android
    @gramyang
    interface 就是个抽象类型,假如这里 p 是 tcpSession 的话它就实现了 getBundle,这里就在做类型断言来确定有没有这个方法
    gramyang
        8
    gramyang  
    OP
       2019-05-28 20:28:30 +08:00
    @whoami9894 我大概明白你的意思了,tcpSession 确实是有 getBundle 方法的,只不过是 tcpSession 的内嵌结构体 CoreProcBundle 有 getBundle 方法,当然这也算 tcpSession 持有这个方法。这里相当于 tcpSession 转换为它的内嵌结构体 CoreProcBundle
    liulaomo
        9
    liulaomo  
       2019-05-28 20:50:09 +08:00
    看代码,这里的 p 只能是一个*tcpSyncConnector 或者*tcpConnector 类型的值,而这两个类型都内嵌了 peer.CoreProcBundle。peer.CoreProcBundle 是有 GetBundle() *CoreProcBundle 这个方法的。所以此类型断言是不会 panic 的。
    liulaomo
        10
    liulaomo  
       2019-05-28 20:51:37 +08:00
    @gramyang
    在线版打不开的话,可以浏览本地版: https://github.com/golang101/golang101
    gramyang
        11
    gramyang  
    OP
       2019-05-28 21:09:12 +08:00
    @liulaomo 我的天!突然冒出来一位野生大神传授我一本自己写的书!感谢分享!!
    acehow
        12
    acehow  
       2019-05-28 21:35:25 +08:00 via Android
    @gramyang 他是无崖子,传功给你这个虚竹。为的是你可以和段誉萧峰一起协助我大宋,抵抗川普的贸易战攻击。
    tairan2006
        13
    tairan2006  
       2019-05-29 09:13:13 +08:00 via Android
    这种一般都是设计有问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   967 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:02 · PVG 06:02 · LAX 14:02 · JFK 17:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.