说明:我只是在学习GO,并且遇到了这个问题。
我正在尝试实现一个“类”,该类继承一个方法,该方法调用应该由子类实现的“虚拟”方法。这是我的代码:
https://play.golang.org/p/ysiaPwARkvl
package main
import (
"fmt"
"sync"
)
type Parent struct {
sync.Mutex
MyInterface
}
func (p *Parent) Foo() {
p.Lock()
defer p.Unlock()
p.Bar()
}
func (p *Parent) B(){
panic("NOT IMPLEMENTED")
}
func (p *Parent) A() {
p.Lock()
defer p.Unlock()
p.B()
}
type MyInterface interface {
Foo()
Bar()
}
type Child struct {
Parent
Name string
}
func (c *Child) Bar(){
fmt.Println(c.Name)
}
func (c *Child) B(){
fmt.Println(c.Name)
}
func main() {
c := new(Child)
c.Name = "Child"
// c.A() panic
c.Foo() // pointer error
}
我遗漏了一些有关sync.Mutex的代码,该代码对异步的Child值进行了一些异步更新。
因此,显然在A()或Foo()中,指针p的类型为Parent。我应该如何更改代码,以便A / Foo引用Child类中定义的B / Bar?
答案 0 :(得分:2)
当Go仅提供具有-a 关系(组成)时,您希望具有是-a 关系(继承性):
Child
不是Parent
的一种,因此指向Parent
的指针不能保留指向Child
的指针; Child
已包含 Parent
。由于Parent
和Child
之间没有 is-a 关系,因此Parent.Foo
无法接收Child
类型的对象,也不能它使用Child
实现的任何方法。同样,这意味着Parent
不能直接访问在Child
上定义的任何方法,例如Bar()
或B()
。
通常,Parent
不需要调用Child
中的某些方法。如果是这样,您将为Parent
方法传递一个参数,例如Child
满足您通过该接口调用该方法的接口或调用Child
方法的闭包:
// Use of an interface that Child satisfies.
type Beta interface {
B()
}
func (p *Parent) A(b Beta) {
p.Lock()
defer p.Unlock()
b.B()
}
// Use of a closure.
func (p *Parent) Foo(bar func()) {
p.Lock()
defer p.Unlock()
bar()
}
func callFoo(p *Parent, c *Child) {
callBar := func() {
c.Bar()
}
p.Foo(callBar)
}
func (c *Child) Bar() {
// stub
}
func (c *Child) B() {
// stub
}
您获得的 Child
可以免费调用Parent
方法行为,但它看起来仅类似于继承。 child.Foo()
实际上执行child.Parent.Foo()
,这意味着Parent.Foo
仍然收到Parent
实例(因此得名),而不是Child
实例。
但是,Parent
无法访问Child
未明确共享的有关Child
的任何信息。接口和闭包可以充当类似于C ++中的friend
关键字的两个类之间的机制,只是它们比friend
关键字更具限制性。毕竟,Child
不需要与Parent
共享所有内容,而只需要共享它想要共享的位,有点类似于this pattern in C++。就我个人而言,我更喜欢使用接口,因为它允许您的Parent
“类”使用满足共同接口的多种类型,使其与从普通函数或完全不相关的类型中调用方法几乎相同方法。