【问题标题】:Go - storing structs with the same embedded struct in a listGo - 将具有相同嵌入结构的结构存储在列表中
【发布时间】:2021-11-24 08:59:53
【问题描述】:

我有多个具有相同嵌入式结构的结构。在其中一个结构中,我想存储嵌入基本结构的任何结构的列表。这是一个小sn-p展示这个案例。

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 接口时,一切正常。然而,这种方法完全绕过了类型系统,因为现在所有内容都可以存储在列表中。我想以某种方式表示只有BaseFooBar 可以存储在列表中,以便编译器可以检查是否满足此要求。我的结构没有任何方法,肯定不是那些共享行为并且可以添加到接口的方法。向接口和虚拟实现添加一些虚拟方法似乎非常人为。处理此类场景的 Go 惯用方式是什么?

【问题讨论】:

  • 不确定,您为什么希望它起作用,Bar != Base
  • 我不希望它起作用。我只是怀疑,他可能是实现我想要实现的目标的一种方式。我错了,我不知道什么是正确/惯用的方式。
  • 为了让你的附加工作你想通过类型名称引用匿名嵌入式结构,即bar.Baseplay.golang.org/p/oDvwaymNsaC

标签: go struct interface slice


【解决方案1】:

重要的是相同的界面:

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)
}

【讨论】:

    【解决方案2】:

    您似乎期待的是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
    }
    

    【讨论】:

      【解决方案3】:

      我做了一些搜索和阅读。我想要实现的需要所谓的“总和类型”。目前 Go 不支持 sum 类型。但是,模拟 sum 类型的行为的替代方法很少。在这里Alternatives to sum types in Go 对它们进行了很好的描述。

      更重要的是,看起来在 Go 2 中可能会支持 sum 类型。进一步阅读 proposal: spec: add sum types / discriminated unionsspec: generics: use type sets to remove type keyword in constraints

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-25
        • 1970-01-01
        • 2021-11-27
        • 1970-01-01
        • 2017-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多