尝试将接口{}用于切片以选择随机元素

时间:2013-02-28 06:11:39

标签: go

我一直在尝试实现一个可以从任何类型的切片中随机选择一个元素的函数(比如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

这是对界面{}的有趣滥用吗?有更好的方法吗?

4 个答案:

答案 0 :(得分:5)

Re:有更好的方法吗?

IMO有。 OP方法效率低下简单:

var v []T
...

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

请注意,这两种方法都会对len(v) == 0造成恐慌,直到对此进行预先检查。

答案 1 :(得分:2)

使用反射:

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

答案 2 :(得分:1)

来自language specification

  

两种类型相同或不同。

     

如果两个命名类型的类型名称来源于   相同的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指定给[]接口{}。

答案 3 :(得分:0)

嗯,在所有搜索之后我几乎无法相信,第一个列出的相关问题是: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] 
}

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