返回信息流最近自学go语言,在继承这块遇到一点问题,其实和Java/c++中继承还是有区别的。其实就是一个嵌套类型,但是在外部类型调用内部类型的方法时有个疑问。
方法集提升的规则:
给定一个结构体类型 S 和一个命名为 T 的类型,方法提升像下面规定的这样被包含在结构体方法集中:
?如果 S 包含一个匿名字段 T,S 和 *S 的方法集都包含接受者为 T 的方法提升。
这条规则说的是当我们嵌入一个类型,嵌入类型的接受者为值类型的方法将被提升,可以被外部类型的值和指针调用。
?对于 *S 类型的方法集包含接受者为 *T 的方法提升
这条规则说的是当我们嵌入一个类型,可以被外部类型的指针调用的方法集只有嵌入类型的接受者为指针类型的方法集,也就是说,当外部类型使用指针调用内部类型的方法时,只有接受者为指针类型的内部类型方法集将被提升。
?如果 S 包含一个匿名字段 *T,S 和 *S 的方法集都包含接受者为 T 或者 *T 的方法提升
这条规则说的是当我们嵌入一个类型的指针,嵌入类型的接受者为值类型或指针类型的方法将被提升,可以被外部类型的值或者指针调用。
上面是我golang中文网上找到的关于继承后方法集提升的说明,但是
package main
import "fmt"
type person struct {
name string
}
func (p *person) ppointer(){
fmt.Println("this is person pointer func",p.name)
}
func(p person) pvalue(){
fmt.Println("this is person value func",p.name)
}
type student struct {
person
}
type teacher struct {
*person
}
func main() {
svalue := student{person{"1111"}}
svalue.ppointer()
svalue.pvalue()
//spointer := &student{person{"2222"}}
//spointer.ppointer()
//spointer.pvalue()
//
//tvalue := teacher{&person{"haha"}}
//tvalue.ppointer()
//tvalue.pvalue()
//
//tpointer := &teacher{&person{"啦啦"}}
//tpointer.ppointer()
//tpointer.pvalue()
}
但是这个程序可以正常运行,外部类型值可以直接调用内部类型的接收者为指针的方法,和上面的第一条规则冲突。我的go版本是最新版本12,有没有帮忙大神指点一下迷津,谢谢了。
这是一条镜像帖。来源:北邮人论坛 / golang / #1465同步于 2019/5/21
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Golang机器人发帖
【问题】关于go语言中继承方法集提升的问题
justlikeu
2019/5/21镜像同步8 回复
订阅后,新回复会通过你的通知中心匿名送达。
8 条回复
我的理解是接受指针的方法类似于C++里的传入引用
接受对象的方法是传入对象
看起来差不多,传入指针可以对原对象本身进行修改
p.s. 其实我不会写Golang,以上都是我瞎编的
非常感谢答疑,问题不是值调用方法和指针调用方法的区别[ema3],而是类似多态调用的关系,子类的值类型的方法集并不包括父类的接受者为指针的方法,但是调用的时候却可以进行类型转换,正常运行。不懂方法集的意义在哪[ema1]
【 在 Wizmann 的大作中提到: 】
: 我的理解是接受指针的方法类似于C++里的传入引用
: 接受对象的方法是传入对象
:
golang没有重载,没有多态
想感受一下手写虚函数的恐惧吗?
【 在 justlikeu 的大作中提到: 】
: 非常感谢答疑,问题不是值调用方法和指针调用方法的区别,而是类似多态调用的关系,子类的值类型的方法集并不包括父类的接受者为指针的方法,但是调用的时候却可以进行类型转换,正常运行。不懂方法集的意义在哪
: :
那个其实算一种语法糖,一种编译期限制
在运行时并没有动态决定需要调用哪个函数
好久没写golang了,当时踩的坑都有点忘了。大概的观点就是不要试图在Golang中实现完整的面向对象,害人害己。。。
【 在 justlikeu 的大作中提到: 】
: 接口引用不算多态么
package main
import (
"fmt"
"reflect"
)
type person struct {
name string
}
func (p *person) Ppointer(){
fmt.Println("this is person pointer func",p.name)
}
func(p person) Pvalue(){
fmt.Println("this is person value func",p.name)
}
type student struct {
person
}
type teacher struct {
*person
}
func main() {
svalue := student{person{"1111"}}
// svalue.Ppointer() => (&svalue).Ppointer()
val := reflect.ValueOf(svalue)
n := val.NumMethod()
for i := 0; i < n; i++ {
val.Method(i).Call(nil)
}
spointer := &student{person{"2222"}}
val = reflect.ValueOf(spointer)
n = val.NumMethod()
for i := 0; i < n; i++ {
val.Method(i).Call(nil)
}
tvalue := teacher{&person{"haha"}}
val = reflect.ValueOf(tvalue)
n = val.NumMethod()
for i := 0; i < n; i++ {
val.Method(i).Call(nil)
}
tpointer := &teacher{&person{"啦啦"}}
val = reflect.ValueOf(tpointer)
n = val.NumMethod()
for i := 0; i < n; i++ {
val.Method(i).Call(nil)
}
}