英文:
trying to use interface{} to a slice to select random element
问题
func RandomChoice(a []interface{}, r *rand.Rand) interface{} {
i := r.Int() % len(a)
return a[i]
}
然而,当我尝试将类型为 []float32 的切片传递给第一个参数时,会出现以下错误:
无法将 my_array(类型为 []float32)作为函数参数中的 []interface{} 类型使用
这是对 interface{} 的基本误用吗?有没有更好的方法来实现这个功能?
英文:
I've been trying to implement a function which can randomly select an element from any type of slice (like python's random.choice function)
<!-- language: lang-go -->
func RandomChoice(a []interface{}, r *rand.Rand) interface{} {
i := r.Int()%len(a)
return a[i]
}
However, when I try to pass in a slice of type []float32 into the first argument this error occurs:
<code>cannot use my_array (type []float32) as type []interface {} in function argument</code>
is this a fundemental misuse of interface{}? is there some better way to do this?
答案1
得分: 5
IMO有。OP的方法在简单性方面是低效的:
var v []T
...
// 从 'v' 中选择一个随机元素
e := v[r.Intn(len(v))]
...
请注意,这两种方法在没有进行预先检查的情况下,当 len(v) == 0
时会引发 panic。
英文:
Re: is there some better way to do this?
IMO there is. The OP approach is inefficient wrt to simple:
var v []T
...
// Select a random element of 'v'
e := v[r.Intn(len(v))]
...
Note that both of the approaches will panic for len(v) == 0
until a pre-check for this is made.
答案2
得分: 2
使用反射:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
x := reflect.ValueOf(slice)
return x.Index(r.Intn(x.Len())).Interface()
}
英文:
Using reflection:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
x := reflect.ValueOf(slice)
return x.Index(r.Intn(x.Len())).Interface()
}
答案3
得分: 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{}。
英文:
From the language specification:
> Two types are either identical or different.
>
> Two named types are identical if their type names originate in the
> same TypeSpec. A named and an unnamed type are always different. Two
> unnamed types are identical if the corresponding type literals are
> identical, that is, if they have the same literal structure and
> corresponding components have identical types. In detail:
>
> - Two array types are identical if they have identical element types and
> the same array length.
> - Two slice types are identical if they have
> identical element types.
> - Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical
> types, and identical tags. Two anonymous fields are considered to have
> the same name. Lower-case field names from different packages are
> always different.
> - Two pointer types are identical if they have identical base types.
> - Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types
> are identical, and either both functions are variadic or neither is.
> Parameter and result names are not required to match.
> - Two interface types are identical if they have the same set of methods with the same names and identical function types. Lower-case
> method names from different packages are always different. The order
> of the methods is irrelevant.
> - Two map types are identical if they have identical key and value types.
> - Two channel types are identical if they have identical value types and the same direction.
And:
> A value x is assignable to a variable of type T ("x is assignable to
> T") in any of these cases:
>
> - x's type is identical to T.
> - x's type V and T have identical underlying types and at least one of V or T is not a named type.
> - T is an interface type and x implements T.
> - x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not
> a named type.
> - x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
> - x is an untyped constant representable by a value of type T.
>
>Any value may be assigned to the blank identifier.
The combination of these two results that you can't assign a []MyType to an []interface{}.
答案4
得分: 0
好的,以下是翻译好的部分:
我几乎无法相信,在所有的搜索之后,第一个列出的相关问题是:在Go中将接口切片转换为类型,它基本上包含了答案。
将RandomChoice函数更改为使用答案中描述的InterfaceSlice函数,得到以下结果:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
islice := InterfaceSlice(slice)
i := r.Int()%len(islice)
return islice[i]
}
尽管显然这个答案的性能不是很好,因为它需要将整个切片转换为[]interface{}...
英文:
Well, I can hardly believe after all the searching, that the first listed related question was: Type converting slices of interfaces in go which pretty much contains the answer.
Changing RandomChoice to use the InterfaceSlice function described in the answer to that question yields:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
islice := InterfaceSlice(slice)
i := r.Int()%len(islice)
return islice[i]
}
although apparently this answer is not very well performing, because it requires the entire slice to be converted to []interface{}...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论