英文:
Embedding structs to override methods
问题
我已经翻译好了你的内容:
我在一个名为Manager
的结构体上定义了一些方法,该结构体包含一个Context
。这些Manager
是有版本的,允许新版本只定义已更改的函数,并在未重新定义的情况下自动使用旧版本的函数。
type Context struct { ... }
type Manager1 struct{
Context Context
}
type Manager2 struct {
Manager1
Context Context
}
当在Manager2
上调用一个在Manager2
上未定义的函数时,Context
为nil。有没有一种方法可以使上下文可用?
这个示例比我能解释得更好地演示了这个问题:
http://play.golang.org/p/gFe6GgUKEJ
英文:
TL;DR See playground link at bottom.
I have methods defined on a Manager
struct which contains a Context
. The Manager
s are versioned, allowing a new version to only define functions which have changed, and automatically use the functions from the old version if they are not redefined.
type Context struct { ... }
type Manager1 struct{
Context Context
}
type Manager2 struct {
Manager1
Context Context
}
When calling a function on Manager2
which is not defined on Manager2
the Context
is nil. Is there a way to do this where the context will be available?
This example demonstrates the problem better than I can explain it:
http://play.golang.org/p/gFe6GgUKEJ
答案1
得分: 3
你误用了嵌入。问题在于你在Manager1
上定义了Context
,尽管如此,你在每个后续类型上重新定义了它。在Manager3
中,你设置了它的Context
实例的值。当调用Hello()
时,它被定义在Manager2
上并访问它的Context
实例,该实例没有值。请查看这个示例以演示:http://play.golang.org/p/XebShA9ap4
关键代码是:
m3 = Manager3{Manager2: Manager2{Context: Context{Value: "testing3"}}}
正如你所看到的,如果我实例化嵌入在Manager3
中的Manager2
实例并设置它的Context
值,它会被打印出来。我建议你更改你的类型,使Context
只在Manager1
上定义,然后在初始化类型时使用我示例中的语法。
编辑:为了将评论中讨论的设计写下来,你需要将你的类型更改为以下形式:
type Context struct {
Value string
}
type Manager1 struct {
Context Context
}
type Manager2 struct {
Manager1
}
type Manager3 struct {
Manager2
}
完全删除Manager2
上的Hello()
实现。然后将你的复合字面量初始化更新为以下形式:
m1 := Manager1{Context: Context{Value: "testing1"}}
m2 := Manager2{Manager1: Manager1{Context: Context{Value: "testing2"}}}
m3 := Manager3{Manager2: Manager2{Manager1: Manager1{Context: Context{Value: "testing3"}}}}
英文:
You're misusing embedding. The thing is, you've defined Context
on Manager1
, in spite of that you've redefined it on each subsequent type. In Manager3
you're setting the value for it's Context
instance. When Hello()
is called, it's defined on Manager2
and accesses it's Context
instance which doesn't have a value. Check out this example to demonstrate that http://play.golang.org/p/XebShA9ap4
Money line is:
m3 = Manager3{Manager2: Manager2{Context: Context{Value: "testing3"}}}
As you can see, if I instantiate the Manager2
instance embedded in Manager3
and set it's Context
value it gets printed. I would recommend changing your types so that Context
is only defined on Manager1
and then use syntax like that in my example when you initialize your types.
EDIT: To put the design discussed in comments in writing, you would change your types to this;
type Context struct {
Value string
}
type Manager1 struct {
Context Context
}
type Manager2 struct {
Manager1
}
type Manager3 struct {
Manager2
}
Delete the implementation of Hello()
on Manager2
altogether. Then update your composite-literal initialization to this;
m1 := Manager1{Context: Context{Value: "testing1"}}
m2 := Manager2{Manager1: Manager1{Context: Context{Value: "testing2"}}}
m3 := Manager3{Manager2: Manager2{Manager1: Manager1{Context: Context{Value: "testing3"}}}}
答案2
得分: 2
你误解了通过嵌入结构体调用方法的方式:这只是语法糖!
你可以将m3.Manager2.Hello()
缩写为m3.Hello()
,但是Hello方法从来没有在m3上调用,而是始终在嵌入的Manager2
上调用(该结构体的Contex为nil)。
嵌入不允许“覆盖方法”。嵌入不是子类化,它只是一种语法糖。
英文:
You are misunderstanding calling methods of embedded structs via the embedding struct: This is just syntactic sugar!
You are allowed to abbreviate m3.Manager2.Hello()
to m3.Hello()
but the Hello method is never invoked "on" m3 but always on the embedded Manager2
(which has a nil Contex).
Embedding does not allow to "overwrite methods". Embedding is not subclassing, it is syntactic sugar only.
答案3
得分: 0
您的Manager3
结构包含多个Context
成员 - 您正在设置Manager3.Context
,但打印的是Manager2.Context
。您可能想要做的是从Manager1
和Manager2
中删除冗余的Context
成员,并以以下方式初始化结构体:
var (
m1 = Manager1{Context: Context{Value: "testing1"}}
m2 = Manager2{Manager1: Manager1{Context: Context{Value: "testing2"}}}
m3 = Manager3{Manager2: Manager2{Manager1: Manager1{Context: Context{Value: "testing3"}}}}
)
完整示例请参见:http://play.golang.org/p/13DOYKWN5C
提供访问器或工厂函数可能会使代码更加优雅。
英文:
Your Manager3
struct contains a number of Context
members - you're setting Manager3.Context
, but printing Manager2.Context
. What you're probably looking for is removing the redundant Context
members from Manager1
and Manager2
and initializing the structs this way:
var (
m1 = Manager1{Context: Context{Value: "testing1"}}
m2 = Manager2{Manager1: Manager1{Context: Context{Value: "testing2"}}}
m3 = Manager3{Manager2: Manager2{Manager1: Manager1{Context: Context{Value: "testing3"}}}}
)
Full example here: http://play.golang.org/p/13DOYKWN5C
Providing accessors or factory functions might make this a little nicer.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论