Golang方法覆盖

时间:2016-06-30 13:00:37

标签: inheritance go override

我有以下内容:

type Base struct {

}

func(base *Base) Get() string {
    return "base"
}

func(base *Base) GetName() string {
    return base.Get()
}

我想用Get()的新实现定义一个新类型,这样我就可以使用新类型代替Base,并且在调用GetName()的地方调用新的Get()实现。如果我使用Java,我将继承Base并覆盖Get()。我应该如何在Go中实现这一目标?我希望尽可能避免破坏更改,因此不需要更改Base的现有使用者。

我对此的第一次尝试看起来像..

type Sub struct {
    Base
}

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

..哪个不起作用。我的大脑还没有清楚地连接到Go。

3 个答案:

答案 0 :(得分:1)

Go不是"经典" OO语言:它不知道类和继承的概念。

然而,它确实包含非常灵活的接口概念,可以使用面向对象的许多方面。 Go中的接口提供了一种指定对象行为的方法:如果有什么可以做到这一点,那么可以在这里使用它。

接口定义了一组方法,但这些方法不包含代码:它们没有实现(这意味着它们是抽象的)。

因此,在同一方法中使用不同类型的方法是使用接口。

这是证明它的简单例子:

package main

import (
    "fmt"
)

type Base struct{}
type Baser interface {
    Get() float32
}

type TypeOne struct {
    value float32
    Base
}

type TypeTwo struct {
    value float32
    Base
}

type TypeThree struct {
    value float32
    Base
}

func (t *TypeOne) Get() float32 {
    return t.value
}

func (t *TypeTwo) Get() float32 {
    return t.value * t.value
}

func (t *TypeThree) Get() float32 {
    return t.value + t.value
}

func main() {
    base := Base{}
    t1 := &TypeOne{1, base}
    t2 := &TypeTwo{2, base}
    t3 := &TypeThree{4, base}

    bases := []Baser{Baser(t1), Baser(t2), Baser(t3)}

    for s, _ := range bases {
        switch bases[s].(type) {
        case *TypeOne:
            fmt.Println("TypeOne")
        case *TypeTwo:
            fmt.Println("TypeTwo")
        case *TypeThree:
            fmt.Println("TypeThree")
        }

        fmt.Printf("The value is:  %f\n", bases[s].Get())
    }   
}

Go Playground

答案 1 :(得分:1)

接口是方法签名的命名集合:
见:https://gobyexample.com/interfaces
并且:http://www.golangbootcamp.com/book/interfaces
所以最好不要以这种OOP方式使用。

你问的不是Golang惯用语 但可能(2种方式):

这就是您所需要的(工作示例代码):

package main

import "fmt"

type Base struct {
}

func (base *Base) Get() string {
    return "base"
}

type Getter interface {
    Get() string
}

func (base *Base) GetName(getter Getter) string {
    if g, ok := getter.(Getter); ok {
        return g.Get()
    } else {
        return base.Get()
    }
}

// user code :
type Sub struct {
    Base
}

func (t *Sub) Get() string {
    return "Sub"
}
func (t *Sub) GetName() string {
    return t.Base.GetName(t)
}

func main() {
    userType := Sub{}
    fmt.Println(userType.GetName()) // user string
}

输出:

Sub

如您所见,必须在用户代码中完成一个初始化代码:

func (t *Sub) GetName() string {
    return t.Base.GetName(t)
}

这也有效:

package main

import "fmt"

type Getter interface {
    Get() string
}

type Base struct {
    Getter
}

func (base *Base) Get() string {
    return "base"
}

func (base *Base) GetName() string {
    return base.Getter.Get()
}

// user code :
type Sub struct {
    Base
}

func (t *Sub) Get() string {
    return "Sub"
}
func New() *Sub {
    userType := &Sub{}
    userType.Getter = interface{}(userType).(Getter)
    return userType
}

func main() {
    userType := New()
    fmt.Println(userType.GetName()) // user string
}

输出:

Sub

如您所见,必须在用户代码中完成一个初始化代码:

userType.Getter = interface{}(userType).(Getter)

答案 2 :(得分:0)

这里是如何“覆盖”方法并从封装结构访问它:

package main

import (
    "fmt"
)

type Getter interface {
    Get() string
}

type Base struct {
}

type Sub1 struct {
    Base // reuse fields and methods
}

type Sub2 struct {
    Base // reuse fields and methods
}

func(base *Base) Get() string {
    return "getBase" 
}

func(sub1 *Sub1) Get() string {
    return "getSub1" // override base method
}


func(sub1 Sub1) CallOverriden() string {
    return sub1.Get()
}

func(sub1 Sub1) CallBase() string {
    return sub1.Base.Get() // access and expose encapsulated/embedded method
}


func main() {
    var g Getter
    g = &Sub1{}
    
    fmt.Println(g.Get()) // getSub1
    
    g = &Sub2{}
    fmt.Println(g.Get()) // getBase // not-overriden method
    
    fmt.Println(Sub1{}.CallOverriden())
    fmt.Println(Sub1{}.CallBase()) // "base" method can be exposed
}