尝试使用interface{}将切片转换为选择随机元素。

huangapple go评论148阅读模式
英文:

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 &#39;v&#39;
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{}...

huangapple
  • 本文由 发表于 2013年2月28日 14:11:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/15128692.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定