1

我一直在尝试实现一个可以从任何类型的切片中随机选择一个元素的函数(比如 python 的 random.choice 函数)

func RandomChoice(a []interface{}, r *rand.Rand) interface{} {
    i := r.Int()%len(a)
    return a[i]
}

但是,当我尝试将 []float32 类型的切片传入第一个参数时,会发生此错误:

cannot use my_array (type []float32) as type []interface {} in function argument

这是对 interface{} 的根本滥用吗?有没有更好的方法来做到这一点?

4

4 回答 4

5

回复:有没有更好的方法来做到这一点?

海事组织有。OP 方法效率低下至简单:

var v []T
...

// Select a random element of 'v'
e := v[r.Intn(len(v))]   
...

请注意,在len(v) == 0对此进行预检查之前,这两种方法都会恐慌。

于 2013-02-28T07:22:42.063 回答
2

使用反射:

func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
    x := reflect.ValueOf(slice)
    return x.Index(r.Intn(x.Len())).Interface()
}
于 2013-02-28T10:02:19.647 回答
1

语言规范

两种类型要么相同,要么不同。

如果两个命名类型的类型名称源自相同的 TypeSpec,则它们是相同的。命名类型和未命名类型总是不同的。如果对应的类型字面量相同,即如果它们具有相同的字面量结构并且对应的组件具有相同的类型,则两个未命名类型是相同的。详细地:

  • 如果两个数组类型具有相同的元素类型和相同的数组长度,则它们是相同的。
  • 如果两个切片类型具有相同的元素类型,则它们是相同的。
  • 如果两个结构类型具有相同的字段序列,并且相应的字段具有相同的名称、相同的类型和相同的标签,则它们是相同的。两个匿名字段被认为具有相同的名称。来自不同包的小写字段名称总是不同的。
  • 如果两个指针类型具有相同的基类型,则它们是相同的。
  • 如果两个函数类型相同,如果它们具有相同数量的参数和结果值,对应的参数和结果类型相同,并且两个函数都是可变参数,或者两者都不是。参数和结果名称不需要匹配。
  • 如果两个接口类型具有相同名称和相同函数类型的相同方法集,则它们是相同的。来自不同包的小写方法名称总是不同的。方法的顺序无关紧要。
  • 如果两个映射类型具有相同的键和值类型,则它们是相同的。
  • 如果两个通道类型具有相同的值类型和相同的方向,则它们是相同的。

和:

在以下任何一种情况下,值 x 都可分配给 T 类型的变量(“x 可分配给 T”):

  • x 的类型与 T 相同。
  • x 的类型 V 和 T 具有相同的基础类型,并且 V 或 T 中的至少一个不是命名类型。
  • T 是一个接口类型,x 实现了 T。
  • x 为双向通道值,T 为通道类型,x 的类型 V 和 T 具有相同的元素类型,且 V 或 T 至少有一个不是命名类型。
  • x 是预先声明的标识符 nil,T 是指针、函数、切片、映射、通道或接口类型。
  • x 是一个无类型的常量,可以用 T 类型的值表示。

任何值都可以分配给空白标识符。

这两个结果的组合表明您无法将 []MyType 分配给 []interface{}。

于 2013-02-28T07:07:50.533 回答
0

好吧,经过所有的搜索,我几乎无法相信,第一个列出的相关问题是:在 go 中类型转换接口切片,其中几乎包含了答案。将 RandomChoice 更改为使用该问题的答案中描述的 InterfaceSlice 函数会产生:

func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
    islice := InterfaceSlice(slice)
    i := r.Int()%len(islice)
    return islice[i] 
}

虽然显然这个答案的表现不是很好,因为它需要将整个切片转换为 []interface{} ...

于 2013-02-28T06:36:22.957 回答