V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
seth19960929
V2EX  ›  问与答

golang 的组合是一个虚假的继承~~~

  •  
  •   seth19960929 · 2021-03-29 17:35:05 +08:00 · 1444 次点击
    这是一个创建于 1122 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天写代码遇到了一个坑:

    package main
    
    import "fmt"
    
    type Person interface {
    	Say()
    	Name()
    }
    
    type Parent struct {
    }
    
    func (s *Parent) Say() {
    	fmt.Println("i am " + s.Name())
    }
    
    func (s *Parent) Name() string {
    	return "parent"
    }
    
    type Child struct {
    	Parent
    }
    
    func (s *Child) Name() string {
    	return "child"
    }
    
    func main() {
    
    	var c Child
    	// i am parent
    	c.Say()
    
    	c1 := &Child{}
        // i am parent
        c1.Say()
    }
    
    

    这个输出 // i am parent, 感觉 go 的组合真的和继承没有任何关系.

    11 条回复    2021-03-31 09:37:03 +08:00
    yokyj
        1
    yokyj  
       2021-03-29 17:56:27 +08:00
    golang 确实是没有真正的继承,但是你这里的问题是在于 Child 没有实现 Say 函数,也就是没有实现 person 接口
    anonydmer
        2
    anonydmer  
       2021-03-29 18:10:43 +08:00
    接口根本没用上,而且 Name() 函数接口和实现中签名也不一致
    jasonkayzk
        4
    jasonkayzk  
       2021-03-29 20:01:54 +08:00
    首先,你的 interface 写的有问题,Name() 函数应该是有返回值的,否则下面的 struct 是没有实现这个接口的:

    ```go
    type Person interface {
    Say()
    Name() string
    }
    ```

    其次,要注意 Go 里面只有 “组合”(类似于 Spring 框架里面通过组合进行依赖注入?),没有继承;

    在组合的时候,子 struct 会保留原来父 struct 中的方法(除非子类重写这个方法);并且 Go 中的方法(或者说函数)只有 Receiver 的说法,而不是属于某个类或者子类!

    所以,当子类 Child 调用 Say 方法的时候,由于 Child 本身没有实现 Child 方法,所以会调用到 Child 组合而来的 Parent ;
    如果你给 Parent 成员变量取个名字,例如:

    ```go
    type Child struct {
    p Parent
    }
    ```

    其实他调用的是 c.p.Name();

    大概这样。
    cmdOptionKana
        5
    cmdOptionKana  
       2021-03-29 20:15:34 +08:00 via Android
    真正的继承有很多问题,因此比较新的语言都看轻了继承,一些老语言也增加非继承的组合的支持。
    tabris17
        6
    tabris17  
       2021-03-29 20:45:40 +08:00 via iPhone
    是你的代码有问题,s.Name()调用是静态绑定的,如果此处要实现动态分发,那就要先实现一个包含 Name()方法的 named 接口,然后把 s 转换成接口再调用
    rrfeng
        7
    rrfeng  
       2021-03-29 21:15:13 +08:00   ❤️ 1
    你这个 Person 没有任何卵用(逃
    seth19960929
        8
    seth19960929  
    OP
       2021-03-30 10:14:18 +08:00
    @yokyj 是呀
    @anonydmer 忽略我的错误. 改正了
    @jasonkayzk 已修正
    @cmdOptionKana 比如说?
    seth19960929
        9
    seth19960929  
    OP
       2021-03-30 10:15:00 +08:00
    @rrfeng 因为我在别的方法需要使用 Person 接口, 只是实例代码没用
    seth19960929
        10
    seth19960929  
    OP
       2021-03-30 10:25:16 +08:00
    @tabris17 我要表达的是组合的方式, 和接口无关. 我的其他代码没给. 一样是用 Person 接口去调用.
    tabris17
        11
    tabris17  
       2021-03-31 09:37:03 +08:00
    @seth19960929 组合就用显式调用,4 楼已经说了。如果要实现动态分发(多态)就得用接口
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1018 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 19:57 · PVG 03:57 · LAX 12:57 · JFK 15:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.