我有以下内容:
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。
答案 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())
}
}
答案 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
}