英文:
How to create a slice of structs that embeds another?
问题
我有以下代码:
package main
import "fmt"
type A struct {
Name string
Address string
}
type B struct {
A
}
type C struct {
A
}
type D struct {
A
}
//....更多嵌入A的结构体
type myinterface interface {
SetName(string)
SetAddress(string)
}
func run() *A {
// 遍历嵌入A的结构体切片.... 怎么做呢????
for _, s := range []myinterface{
&B{}, &C{}, &D{},
} {
s.SetName("Bob")
s.SetAddress("Maine")
// 进行其他一些在没有切片的情况下变得非常冗长的操作...
return s.(*A)
}
return nil
}
func main() {
a := run()
fmt.Println(a)
}
我需要遍历所有嵌入A的结构体,但是我很难做到。上面的代码会报错:"cannot use B literal (type *B) as type *A in array or slice literal"。有什么好的方法吗?
英文:
I have the following:
https://play.golang.org/p/q2NUMzbw6-
package main
import "fmt"
type A struct {
Name string
Address string
}
type B struct {
A
}
type C struct {
A
}
type D struct {
A
}
//....more structs that embed A
type myinterface interface {
SetName(string)
SetAddress(string)
}
func run() *A {
// iterate over a slice of structs that embed A.... how????
for _, s := range []*A{
&B{}, &C{}, &D{},
} {
s.SetName("Bob")
s.SetAddress("Maine")
// do some other stuff that gets very verbose w/out a slice...
return s.A
}
}
func main() {
a := run()
fmt.Println(a)
}
I need to iterate through all of the structs that embed A but am having a hard time doing so. The above doesn't work "cannot use B literal (type *B) as type *A in array or slice literal". What is the best way?
答案1
得分: 1
在A上声明满足接口的方法:
func (a *A) SetName(s string) {
a.Name = s
}
func (a *A) SetAddress(s string) {
a.Address = s
}
在范围内使用该接口的切片:
for _, s := range []myinterface{&B{}, &C{}, &D{}} {
...
}
英文:
Declare methods on A that satisfy the interface:
func (a *A) SetName(s string) {
a.Name = s
}
func (a *A) SetAddress(s string) {
a.Address = s
}
Use a slice of that interface in the range:
for _, s := range []myinterface{&B{}, &C{}, &D{}} {
...
}
答案2
得分: 1
这是一个常见的误解,认为Go语言中的类型嵌入与其他语言中的继承类似。
实际上,类型嵌入类似于其他语言中的组合。
在你的例子中,类型 B
和 A
并没有任何关联,除了通过将 A
嵌入到 B
中,你可以直接在 B
上调用 A
的方法。
你可以在这里阅读更多信息:
https://golang.org/doc/effective_go.html#embedding
为了模拟"继承",你需要使用接口。
你应该将 myinterface
作为数组类型,以便以通用的方式处理所有这些结构体。
英文:
It's a common misconception to believe that type embedding in Go is analogous to inheritance in other languages.
In fact, type embedding is analogous to composition in other languages.
In your example, types B
and A
are not related in any way, other than the fact that by embedding A
in B
you are able to invoke A
's methods directly over B
.
You can read more about it here:
https://golang.org/doc/effective_go.html#embedding
In order to mimic "inheritance" you need to work with interfaces.
You should use myinterface
as the array type in order to treat all of those structs in a generic way.
答案3
得分: 0
编译器告诉你问题所在:你不能将类型 B
用作类型 A
(也不能将类型 A
用作类型 B
);这些类型根本不相同。你应该遍历一个 myinterface
切片。
然而,这还不是完整的解决方案,因为 s.A
不起作用,因为 s
现在具有类型 myinterface
(具有底层类型 *B
、*C
和 *D
),并且 myinterface
没有名为 A
的方法。
你可以通过向 myinterface
添加另一个方法 aSelf() *A
并使用接收者类型 *A
实现 aSelf
来解决这个问题,该方法简单地返回接收者。这样,B
、C
等都可以使用这个方法。请注意,在这种情况下,你不能简单地将该方法命名为 A
,因为 B.A
(以及 C.A
等)将是模棱两可的:.A
是指嵌入的 A
字段本身,还是指嵌入的 A
字段的 A
方法?如果该方法不会被导出,你可以将其命名为 a
,否则你需要使用其他名称,如前面提到的 aSelf
。
以下是需要修改/添加的相关部分:
func (a *A) aSelf() *A {
return a
}
type myinterface interface {
SetName(string)
SetAddress(string)
aSelf() *A
}
func run() *A {
// 遍历 myinterface 切片
for _, s := range []myinterface{
&B{}, &C{}, &D{},
} {
s.SetName("Bob")
s.SetAddress("Maine")
// 进行一些其他操作,如果没有切片会变得非常冗长...
return s.aSelf()
}
return nil
}
英文:
The compiler tells you the problem: you can't use type B
as type A
(and you also can't use type A
as type B
); the types simply aren't the same. You should be ranging over a slice of myinterface
.
However, that's not the entire solution because s.A
won't work since s
now has the type myinterface
(with underlying types *B
, *C
, and *D
), and no method named A
belongs to myinterface
.
You can fix this by adding another method aSelf() *A
to myinterface
and implementing aSelf
with a receiver type *A
that simply returns the receiver. This way, B
, C
, etc. can all use this method. Note that you can't simply name the method A
in this instance because B.A
(and C.A
etc.) will be ambiguous: does the .A
refer to the embedded A
field itself or to the A
method of the embedded A
field? You could name it a
if the method will not be exported, else you need to use a different name such as the previously mentioned aSelf
.
Below are the relevant bits to alter/add:
func (a *A) aSelf() *A {
return a
}
type myinterface interface {
SetName(string)
SetAddress(string)
aSelf() *A
}
func run() *A {
// iterate over a slice of myinterface
for _, s := range []myinterface{
&B{}, &C{}, &D{},
} {
s.SetName("Bob")
s.SetAddress("Maine")
// do some other stuff that gets very verbose w/out a slice...
return s.aSelf()
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论