2

According to the code below:

type A struct {
}

func (a *A) Func1(i int) {
    a.Func2(i)
}

func (a *A) Func2(i int) {
    fmt.Println(i)
}

type B struct {
    *A
}

func (b *B) Func2(i int) {
    i += 1
    b.A.Func2(i)
}

func main() {
    var b = B{}
    b.Func1(1)
}

I have a struct A, and 2 functions Func1, Func2 in A, function A.Func1 will call A.Func2.

And I have another struct B that embedding struct A, and have a function Func2 that overriding A.Func2.

When I declare b that has value B{} and call b.Func1(1), it will run A.Func1 and call A.Func2 but not run A.Func1 and call B.Func2 that I override A.Func2 in B.

My question is how can I fix the code so that when I call b.Func1(1), it will run A.Func1 and call B.Func2 that I override A.Func2 in B.

Himanshu
  • 12,071
  • 7
  • 46
  • 61
Yùjǐn Lín
  • 85
  • 1
  • 8
  • 3
    There's no overriding in Go. `B.Func1` works thanks to [embedding](https://golang.org/doc/effective_go.html#embedding). `Func1` is "promoted" to `B`. However, it's still operating on type `A` so it has no way of calling `B.Func2`. – Marc Feb 02 '18 at 10:48
  • 3
    Possible duplicate of [Golang Method Override](https://stackoverflow.com/questions/38123911/golang-method-override) – Marc Feb 02 '18 at 10:49
  • So the only way to fix this problem is copy `A.Func1` to `B.Func1` and change `a.Func2(i)` to `b.Func2(i)`? – Yùjǐn Lín Feb 02 '18 at 10:54
  • Sure, that would work, but at that point you're implementing exactly the same things, it may be better to just make both A and B implement the same interface. – Marc Feb 02 '18 at 10:56
  • In my project, `A` in this code is `http.Client`, I want to use `B` to promote `http.Client.Do` and when I call `B.Get`, `B.Post` ... etc, they will finally call `B.Do` not `http.Client.Do`. I think implement them to a interface probably redundant. Or not at all? – Yùjǐn Lín Feb 02 '18 at 11:07
  • In this case, it's not difficult to implement your own `Get`, `Post`, etc.. methods, those are fairly small and straightforward. So you can just have `B` hold (not embed) a `http.Client` and you implement your own `Do`, `Post`, etc... methods. Whether you use an interface or not depends on whether you want other bits of your code to use your class or a `http.Client` interchangeably. – Marc Feb 02 '18 at 11:12
  • Simply copy go source code to my project and edit a little bit like this? https://play.golang.org/p/nLxiya7tM0x – Yùjǐn Lín Feb 02 '18 at 11:16
  • 1
    Seems about right. I would name `http.Client` though rather than make it embedded. That way you won't have any nasty surprises if someone calls one of the `http.Client` methods not implemented by `B`. – Marc Feb 02 '18 at 11:19
  • I see. Thank you! – Yùjǐn Lín Feb 02 '18 at 11:24

2 Answers2

3

You are calling promoted method a.Func2(i) using b receiver b.A.Func2(i) type. So in actual it is calling the function with receiver A. Since there is no method overriding in go. Only there are embedded types . So you have to create your version of the same function if you wants your function to be used. Like

func (a *B) Func(i int){
    fmt.Println("Calling function from b receiver")
}

can call this in B's Func2

func (b *B) Func2(i int) {
    i += 1
    b.Func(i)
}

Check this question for more details

Himanshu
  • 12,071
  • 7
  • 46
  • 61
3

Using interface you can get a little bit closer the functionality you want.

type F2 interface {
    Func2(i int)
}

func Func1(f2 F2, i int) {
    f2.Func2(i)
}

type A struct {
}

func (a *A) Func2(i int) {
    fmt.Println(i)
}

type B struct {
    *A
}

func (b *B) Func2(i int) {
    i += 1
    b.A.Func2(i)
}

func main() {
    var a = &A{}
    Func1(a,1)

    var b = &B{}
    Func1(b,1)
}
Grzegorz Żur
  • 47,257
  • 14
  • 109
  • 105
  • This works. But if `A.Func1` is from other package, I still need to copy `A.Func1` to `Func1` and rewrite it. – Yùjǐn Lín Feb 02 '18 at 11:11
  • If `A.Func1` is from another package lets say `package new`. Just call the function with package name after importing the package `new`. as `new.A.Func1` – Himanshu Feb 02 '18 at 11:13
  • I mean your `Func1` is not in A, but `Func1` from other package is in `A`. if I want use your answer, I still want to make `A.Func1(...)` to `Func1(A, ...)`. – Yùjǐn Lín Feb 02 '18 at 11:22