在列表中具有相同内嵌结构体的Go存储结构体



我有多个具有相同嵌入结构体的结构体。在其中一个结构体中,我想存储嵌入基结构体的任何结构体的列表。下面是展示这种情况的一小段代码。

package main
type Symbol interface{}
type Base struct {
a int32
}
type Foo struct {
Base
b int32
Symbols []Base
// Below works
// Symbols []Symbol
}
type Bar struct {
Base
c int32
}
func main () {
var bar Bar
var foo Foo
foo.Symbols = append(foo.Symbols, bar)
}

然而,这不起作用。我得到./main.go:25:22: cannot use bar (type Bar) as type Base in append。当我使用空的Symbol接口时,一切都工作了。然而,这种方法完全绕过了类型系统,因为现在所有内容都可以存储在列表中。我想以某种方式表示,只有Base,FooBar可以存储在列表中,这样编译器就可以检查这个rquirement是否满足。我的结构没有任何方法,当然不是那些共享行为并可以添加到接口的方法。向接口和虚拟实现添加一些虚拟方法似乎非常不真实。处理这种场景的Go惯用方法是什么?

重要的是相同的界面:

package main
import (
"fmt"
)
type Item interface{
fmt.Stringer
}
type ItemA struct {
}
func (a ItemA) String() string {
return "item A"
}
type ItemB struct {
}
func (a ItemB) String() string {
return "item B"
}
func main() {
items := make([]Item, 0)
items = append(items, ItemA{}, ItemB{})
fmt.Printf("Items: %v", items)
}

你似乎期待的是subtype polymorphism。Go不支持非接口类型的动态绑定。因此你可以使用接口

package main
func main(){
var bar Bar
var foo Foo
foo.Symbols = append(foo.Symbols, bar)
}
type Symbol interface {
Symbol()
}
type Base struct {
a int32
}
func (b Base)Symbol(){}
type Foo struct {
Base
b int32
Symbols []Symbol
}
type Bar struct {
Base
c int32
}

或者如果你不喜欢使用接口,你可以使用下面的技巧来反射。

package main
import "fmt"
func main(){
var bar Bar
var foo Foo
err := foo.AddSymbol(bar)
if err != nil{
fmt.Println(err)
}
}
type Base struct {
a int32
}
func (b Base)Symbol(){}
type Foo struct {
Base
b int32
symbol []interface{} // field made private
}
// AddSymbol : helper to append values
func (f *Foo)AddSymbol(in interface{})(err error){
if f.symbol == nil{
f.symbol = make([]interface{},0)
}
switch typ := in.(type) {
case Base,Bar,Foo:
f.symbol = append(f.symbol,in)
default:
return fmt.Errorf("provided type: %s is not supported",typ)
}
return nil
}
type Bar struct {
Base
c int32
}

我做了一些搜索和阅读。我想要达到的是所谓的"总和型"。目前Go不支持sum类型。然而,很少有其他方法可以模拟sum类型的行为。它们在这里很好地描述了Go中求和类型的替代方法。

更重要的是,看起来在Go 2中可能会支持sum类型。进一步阅读建议:spec: add sum types/discriminated union, spec: generics: use type sets删除约束中的type关键字。

最新更新