试图使用接口{}到切片选择

问题描述:

我一直试图实现可随机地从任何类型的片的选择的元件(如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

这是接口的误用fundemental {}?有没有更好的方法来做到这一点?

好吧,我完全不能相信所有的搜索,第一个相关的问题是:Type converting slices of interfaces in go这几乎包含答案。 更改RandomChoice使用在这个问题的答案的产量描述的InterfaceSlice功能:

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

虽然显然该答案不​​是非常好执行,因为它要求在整个切片要被转换为[]接口{}。 ..

language specification

两种类型相同或不同。

如果两个命名类型的类型名称始于 相同的TypeSpec,则它们是相同的。一个有名和无名的类型总是不同的。两个 未命名类型是相同的,如果相应的类型文字是 相同,即如果它们具有相同的文字结构和 相应的组件具有相同的类型。详细说明如下:

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

和:

  • X的:

    甲值x可分配给类型T的变量在任何这些情况下( “x是分配给 T”)类型与T相同。

  • x的类型V和T具有相同的基础类型,并且V或T中的至少一个不是指定类型。
  • T是一个接口类型以及x实现T.
  • x是一个双向信道值,T是一个信道类型,x的V型和T具有相同的元素类型,和V中的至少一种或T不 一个命名的类型。
  • x是预定义的标识符nil,T是指针,函数,片,映射,通道或接口类型。
  • x是由

任何值可以被分配给空白标识符类型T的值的类型化表示的常数。

这两个结果的组合不能将[] MyType指定给[]接口{}。

+0

谢谢你们回答我的问题的一部分。我也喜欢斯蒂芬在我的回答中的引用:“在Go中,有一条通用规则,语法不应该隐藏复杂/昂贵的操作。” – kellpossible 2013-02-28 08:44:30

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

IMO有。该OP方法是低效WRT简单:

var v []T 
... 

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

注意,直到该预检查,这两个办法都将惊恐的len(v) == 0

+0

感谢您的回答!虽然我不完全确定我理解这个术语。你是否建议最好不要使用RandomChoice之类的函数? – kellpossible 2013-02-28 08:42:28

+2

是的,这就是我的意思。没有类型转换/断言,静态类型检查和更好的运行时间性能,用于编写大约十几个字符。这可能甚至比'e:= RandomChoice(a,r)。(T)'少得多。 – zzzz 2013-02-28 09:07:45

使用反射:

func RandomChoice(slice interface{}, r *rand.Rand) interface{} { 
    x := reflect.ValueOf(slice) 
    return x.Index(r.Intn(x.Len())).Interface() 
}