6
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".

QthCN
  • 127
  • 1
  • 6

2 Answers2

9

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.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Using interface it means you have to multiple the code, like `WhoAmI` method, it repeatedly shows in both `Sub` and `Parent` struct. I think passing object and use `reflect.ValueOf(&Sub{}).MethodByName("WhoAmI").Call(nil)` is a better option – TomSawyer May 16 '18 at 08:03
2

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{})
}
Todd Yandell
  • 14,656
  • 2
  • 50
  • 37