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

2021-03-29 17:35:05 +08:00
 seth19960929

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

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 的组合真的和继承没有任何关系.

1585 次点击
所在节点    问与答
11 条回复
yokyj
2021-03-29 17:56:27 +08:00
golang 确实是没有真正的继承,但是你这里的问题是在于 Child 没有实现 Say 函数,也就是没有实现 person 接口
anonydmer
2021-03-29 18:10:43 +08:00
接口根本没用上,而且 Name() 函数接口和实现中签名也不一致
kingwrcy
2021-03-29 18:16:52 +08:00
1.Person 接口根本没用到.

2.另外如果要实现你这个,需要在 Parent 结构体中 定义一个 name 的属性,初始化的时候传入,而不是硬编码在 Name 函数里.

3.golang 没说过自己有继承吧?一直说的都是组合. https://golang.org/doc/effective_go#embedding
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
2021-03-29 20:15:34 +08:00
真正的继承有很多问题,因此比较新的语言都看轻了继承,一些老语言也增加非继承的组合的支持。
tabris17
2021-03-29 20:45:40 +08:00
是你的代码有问题,s.Name()调用是静态绑定的,如果此处要实现动态分发,那就要先实现一个包含 Name()方法的 named 接口,然后把 s 转换成接口再调用
rrfeng
2021-03-29 21:15:13 +08:00
你这个 Person 没有任何卵用(逃
seth19960929
2021-03-30 10:14:18 +08:00
@yokyj 是呀
@anonydmer 忽略我的错误. 改正了
@jasonkayzk 已修正
@cmdOptionKana 比如说?
seth19960929
2021-03-30 10:15:00 +08:00
@rrfeng 因为我在别的方法需要使用 Person 接口, 只是实例代码没用
seth19960929
2021-03-30 10:25:16 +08:00
@tabris17 我要表达的是组合的方式, 和接口无关. 我的其他代码没给. 一样是用 Person 接口去调用.
tabris17
2021-03-31 09:37:03 +08:00
@seth19960929 组合就用显式调用,4 楼已经说了。如果要实现动态分发(多态)就得用接口

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/766231

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX