【问题标题】:golang 2 slice types with 1 fieldgolang 2个切片类型,1个字段
【发布时间】:2014-09-19 00:19:25
【问题描述】:

鉴于golang不支持联合,最好的实现方式是:

type foo struct {
    words []string
    nums []int
}

这样一次只能使用wordsnums。我尝试过的一件事是:

type foo struct {
    values []interface{}
}

但我更喜欢将类型限制为提到的两种或带有指针的东西。

【问题讨论】:

标签: struct go union


【解决方案1】:

使用foo 包来隐藏实现。例如,

package foo

const (
    typeWords = iota + 1
    typeNums
)

type Foo struct {
    fooType byte
    words   []string
    nums    []int
}

func NewWords(words []string) *Foo {
    return &Foo{fooType: typeWords, words: words}
}

func NewNums(nums []int) *Foo {
    return &Foo{fooType: typeNums, nums: nums}
}

func (f *Foo) Words() []string {
    if f.fooType != typeWords {
        return nil
    }
    return f.words
}

func (f *Foo) Nums() []int {
    if f.fooType != typeNums {
        return nil
    }
    return f.nums
}

附录:

由于我们隐藏了包foo的实现,我们可以用另一种方式实现它。比如我们可以采纳twinj的建议,使用一个接口。为了确保某种程度的通用性,让我们添加另一个[]string 类型Phrases。值类型用于区分[]string 两种类型。

package foo

type (
    valueWords   []string
    valuePhrases []string
    valueNums    []int
)

type Foo struct {
    value interface{}
}

func NewWords(words []string) *Foo {
    return &Foo{value: valueWords(words)}
}

func (f *Foo) Words() []string {
    value, ok := f.value.(valueWords)
    if !ok {
        return nil
    }
    return value
}

func NewPhrases(phrases []string) *Foo {
    return &Foo{value: valuePhrases(phrases)}
}

func (f *Foo) Phrases() []string {
    value, ok := f.value.(valuePhrases)
    if !ok {
        return nil
    }
    return value
}

func NewNums(nums []int) *Foo {
    return &Foo{value: valueNums(nums)}
}

func (f *Foo) Nums() []int {
    value, ok := f.value.(valueNums)
    if !ok {
        return nil
    }
    return value
}

【讨论】:

  • 小提示:使用 "typeWords = iota" 而不是 "typeWords = iota + 1" 似乎同样有效
  • @lf215:不,不是。我不希望类型的零值有效。只有在 foo 包中显式创建时才有效。例如,var f foo.Foo 对于fooType 将为零; fooType 未定义。
  • 不错;我还将添加一个使用类型开关返回类型的方法,以及一个检查 Foo 是否已初始化的方法,因为 value 是私有的。
【解决方案2】:

另一种选择是使用接口和类型断言。

type Foo struct {
    values interface{}
}

func (o *Foo) Words() []string {
    if v, ok := o.values.([]string); ok {
        return v 
    }
    return nil
}

func (o *Foo) Nums() []int {
     if v, ok := o.values.([]int); ok {
        return v
    }
    return nil
}

查看 Go 操场示例:GoPlay

注意:

  1. Foo 不能是接口类型(类型 Foo []interface{} 或类型 Foo 接口{}),但可以是包含接口类型的结构。

  2. 您也不能将 []interface{} 断言为另一个切片类型,因为 []interface{} 本身就是一种类型。 See here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 2016-05-25
    • 2013-10-23
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 1970-01-01
    相关资源
    最近更新 更多