在父类方法中如何调用子类方法?

huangapple go评论75阅读模式
英文:

how to call child method in parent method?

问题

包含翻译的代码如下:

package main

import "fmt"

type Super struct{}

func (super *Super) name() string {
	return "Super"
}

func (super *Super) WhoAmI() {
	fmt.Printf("I'm %s.\n", super.name())
}

type Sub struct {
	Super
}

func (sub *Sub) name() string {
	return "Sub"
}

func main() {
	sub := &Sub{Super{}}
	sub.WhoAmI()
}

我想要得到"I'm Sub",但实际上得到的是"I'm Super"。

我已经知道sub.WhoAmI会调用sub.Super.WhoAmI,但我仍然想知道是否有一种方法可以得到"I'm Sub"。在Python中,当我编写以下代码时:

class Super(object):

    def name(self):
        return "Super"

    def WhoAmI(self):
        print("I'm {name}".format(name=self.name()))

class Sub(Super):

    def name(self):
        return "Sub"


if __name__ == "__main__":
    sub = Sub()
    sub.WhoAmI()

我可以得到"I'm Sub"。

英文:
package main

import "fmt"

type Super struct{}

func (super *Super) name() string {
	return "Super"
}

func (super *Super) WhoAmI() {
	fmt.Printf("I'm %s.\n", super.name())
}

type Sub struct {
	Super
}

func (sub *Sub) name() string {
	return "Sub"
}

func main() {
	sub := &Sub{Super{}}
	sub.WhoAmI()
}

I want to get "I'm Sub", but I get "I'm Super" instead.

I already know sub.WhoAmI will call sub.Super.WhoAmI, but I still want to know if there is a way to get "I'm Sub". In Python when I write following code:

class Super(object):

    def name(self):
        return "Super"

    def WhoAmI(self):
        print("I'm {name}".format(name=self.name()))

class Sub(Super):

    def name(self):
        return "Sub"


if __name__ == "__main__":
    sub  = Sub()
    sub.WhoAmI()

I can get "I'm Sub".

答案1

得分: 9

嵌入不是子类化。Go语言中没有超类或子类的概念。这里的Sub不是Super的"子类",它包含了一个Super。你不能做你试图做的事情。你需要以一种不同的方式组织你的代码,这样就不需要这样做。

例如,在Go语言中,可以使用以下更自然的方式来实现这个功能(playground):

package main

import "fmt"

type Namer interface {
    Name() string
}

type Super struct{}

func (sub *Super) Name() string {
    return "Super"
}

type Sub struct{}

func (sub *Sub) Name() string {
    return "Sub"
}

func WhoAmI(namer Namer) {
    fmt.Printf("I'm %s.\n", namer.Name())
}

func main() {
    sub := &Sub{}
    WhoAmI(sub)
}

与其关注类(Go语言中没有类的概念),这里关注的是接口。这不是关于事物的"是什么",而是关于它们能做什么。这是一种非常强大的编程方法,实际上通常比继承抽象更灵活、更不容易出错。

英文:

Embedding is not subclassing. There are no superclasses or subclasses in Go. Sub here is not a "child" of Super. It contains a Super. You can't do you're trying to do. You need to organize your code in a different way so that it's not needed.

For example, here (playground) is a more natural way to do this in Go:

package main

import "fmt"

type Namer interface {
	Name() string
}

type Super struct{}

func (sub *Super) Name() string {
	return "Super"
}

type Sub struct{}

func (sub *Sub) Name() string {
	return "Sub"
}

func WhoAmI(namer Namer) {
	fmt.Printf("I'm %s.\n", namer.Name())
}

func main() {
	sub := &Sub{}
	WhoAmI(sub)
}

Rather than focus on classes (which Go doesn't have), this focuses on interfaces. It's not a question of what things are, it's a question of what they can do. This is a very powerful approach to programming, and in practice is often much more flexible and less error-prone than inheritance abstractions.

答案2

得分: 2

在Go语言中,将函数视为属于单个命名空间的一部分。Go实际上没有类、方法或继承,所以你尝试的方式永远不会起作用。

换句话说,当你定义一个函数时,比如:

func (f *Foo) DoStuff()

你可以将其想象为实际上是这样定义的:

func DoStuff(f *Foo)

所以你可能会注意到为什么Go选择调用Super结构体上的name函数——它是唯一匹配的函数签名。(请注意,在你的WhoAmI函数中,super被定义为super *Super,所以Go将其与相同类型的相应函数匹配起来。)

至于如何按照Go的方式来做,可以尝试使用接口:

http://play.golang.org/p/8ELw-9e7Re

package main

import "fmt"

type Identifier interface {
    WhoAmI() string
}

type A struct{}

func (a *A) WhoAmI() string {
    return "A"
}

type B struct{}

func (b *B) WhoAmI() string {
    return "B"
}

func doSomething(x Identifier) {
    fmt.Println("x is a", x.WhoAmI())
}

func main() {
    doSomething(&A{})
    doSomething(&B{})
}
英文:

Think of functions in Go as if they all belong to a single namespace. Go really doesn’t have classes, methods, or inheritance, so what you’re attempting will never work the way you intend.

To put it another way, when you define a function like this:

func (f *Foo) DoStuff()

You can imagine it really being defined as:

func DoStuff(f *Foo)

So you might notice why Go chose to call the name function on your Super struct—it was the only function signature that matched. (Note that in your WhoAmI function super is defined as super *Super so Go matches it up with the corresponding function of the same type.)

As for how you might do this the Go way, try using interfaces:

http://play.golang.org/p/8ELw-9e7Re

package main

import "fmt"

type Indentifier interface {
	WhoAmI() string
}

type A struct{}

func (a *A) WhoAmI() string {
	return "A"
}

type B struct{}

func (b *B) WhoAmI() string {
	return "B"
}

func doSomething(x Indentifier) {
	fmt.Println("x is a", x.WhoAmI())
}

func main() {
	doSomething(&A{})
	doSomething(&B{})
}

huangapple
  • 本文由 发表于 2015年11月18日 23:04:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/33783491.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定