dtpt75860 2019-06-21 00:32
浏览 93
已采纳

如何使用子方法强制多态?

I'm coming from a language like C++ where OOP is well defined and polymorphism is commonly used. I'm new using Go and I'm trying to call child method from a polymorphism and I have no idea what's is the right pattern.

I created two structs as u'll see, and I defined 2 methods fun1 and fun2 where in the base struct i override only one of them, and in the parent i'm calling it. If the polymorphism is correct, this child method should be called and at least in my example, this is not happenning

Here is the code:

package main

import (
    "fmt"
)

type A struct {

}

type B struct {
    A
}

func (a* A) fun1() {
    fmt.Println("I'm in A.fun1()")
    a.fun2()
}

func (a* A) fun2() {
    fmt.Println("I'm in A.fun2()")
}


func (b* B) fun2() {
    fmt.Println("I'm in B.fun2()")
}

func main() {
    b := B{}
    b.fun1()    
}

You can try it here: https://play.golang.org/p/s7xZun-6Otx

The output was

I'm in A.fun1()
I'm in A.fun2()

and I wasexpected

I'm in A.fun1()
I'm in B.fun2()

How can I do that? what's the right way for having a good design in Go for this?

Regards

  • 写回答

1条回答 默认 最新

  • dongshan4518 2019-06-21 01:15
    关注

    Go objects are generally built around composition as opposed to inheritance, as the pattern you are using would make it very difficult for the A structure to make any assumptions about what fun2 is doing. The polymorphism in go is done at the interface level. The preferred method is to pull the "overridable" fun2 functionality into a separate interface type, which is passed in to the fun1 function or stored in the object containing fun1. Without the specifics of how you would be doing this, it's difficult to make a reasonable example but this is the pattern:

    package main
    
    import (
        "fmt"
    )
    
    type fun2er interface {
        fun2()
    }
    
    type A struct {
        B fun2er
    }
    
    func (a* A) fun1() {
        fmt.Println("I'm in A.fun1()")
        a.B.fun2()
    }
    
    type B1 struct {}
    
    func (b B1) fun2() {
        fmt.Println("I'm in B1.fun2()")
    }
    
    type B2 struct {}
    
    func (b B2) fun2() {
        fmt.Println("I'm in B2.fun2()")
    }
    
    func main() {
        a1 := A{B: B1{}}
        a2 := A{B: B2{}}
    
        a1.fun1()
        a2.fun1()
    }
    

    This will print:

    I'm in A.fun1()
    I'm in B1.fun2()
    I'm in A.fun1()
    I'm in B2.fun2()
    

    Edit:

    I wanted to add a little more color on how this works under the hood. The way you are "extending" your A type with B is called struct embedding, and is mostly syntactic sugar for adding a field to B of type A named the same as its type:

    type A struct {}
    
    type B struct {
        A A
    }
    

    The key difference being that when using struct embedding you can call A methods directly on a B object b.fun1(). When this is called, the this-like a parameter that gets passed to fun1 is not the entire B object, but just the A field inside of it (as though you called b.A.fun1()) which is why when fun1 calls fun2, it is calling the A implementation, as it has no access to the B object it is stored inside.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序
  • ¥15 onvif+openssl,vs2022编译openssl64
  • ¥15 iOS 自定义输入法-第三方输入法
  • ¥15 很想要一个很好的答案或提示
  • ¥15 扫描项目中发现AndroidOS.Agent、Android/SmsThief.LI!tr
  • ¥15 怀疑手机被监控,请问怎么解决和防止
  • ¥15 Qt下使用tcp获取数据的详细操作
  • ¥15 idea右下角设置编码是灰色的
  • ¥15 全志H618ROM新增分区
  • ¥15 在grasshopper里DrawViewportWires更改预览后,禁用电池仍然显示