如何将一个未知类型的数组转换为 type []any 类型?

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

How do you cast an array of unknown type to type []any?

问题

假设只有数组作为参数传递给arr参数,我希望每次调用unpackArray()时,返回的参数都是从其原始数组类型转换为[]any类型的。

package main

func unpackArray(arr any) []any {
	return arr.([]any)
}

func main() {
	myArr1 := []string {"Hey"}
	myArr2 := []int {60}
	unpackArray(myArr1)
	unpackArray(myArr2)
}

然而,这段代码会产生错误panic: interface conversion: interface {} is []string, not []interface {}。因此,它不允许我将静态类型不是[]any的接口转换为[]any类型。

所以,假设我知道arr的静态类型是某种数组类型,并且不改变arr参数的初始化类型(any),我该如何使用这个函数将arr转换为[]any类型呢?

(我在处理映射时遇到了相同的问题,无法将任意映射类型转换为map[any]any类型,但我猜想解决这个问题的方法与数组的解决方法类似。)

英文:

Assuming only arrays are passed as arguments to the arr parameter, I would like each call of unpackArray() to return the argument casted from its original array type to type []any.

package main

func unpackArray(arr any) []any {
	return arr.([]any)
}

func main() {
	myArr1 := []string {"Hey"}
	myArr2 := []int {60}
	unpackArray(myArr1)
	unpackArray(myArr2)
}

However, this code yields error panic: interface conversion: interface {} is []string, not []interface {}. So it is not allowing me to cast an interface whose static type is not type []any to type []any.

So, given I know that arr's static type is some type of array, and without changing the arr parameter's initialization type from any, how could I convert arr to type []any using this function?

(I am encountering the same problem with maps where I cannot cast from an arbitrary map type to type map[any]any, but I am guessing the solution to this issue would be similar to the solution for arrays.)

答案1

得分: 1

Go语言没有像这样的内置“转换”,但是你可以编写一个函数来实现。

你可以使用反射将任意类型的切片转换为[]any

func unpackArray(s any) []any {
    v := reflect.ValueOf(s)
    r := make([]any, v.Len())
    for i := 0; i < v.Len(); i++ {
        r[i] = v.Index(i).Interface()
    }
    return r
}

你也可以在Go 1.18或更高版本中使用泛型:

func unpackArray[S ~[]E, E any](s S) []any {
    r := make([]any, len(s))
    for i, e := range s {
        r[i] = e
    }
    return r
}

这两个版本的函数都可以按照问题中的要求工作:

myArr1 := []string {"Hey"}
myArr2 := []int {60}
unpackArray(myArr1)
unpackArray(myArr2)

注意:

  • Go语言没有像其他一些语言那样的“转换”。Go语言有相关的type assertionconversion功能。
  • 表达式arr.([]any)是一个类型断言。该表达式断言接口arr中的具体值具有类型[]any。该表达式不执行任何转换。
  • 问题中的代码使用的是slices,而不是arrays
英文:

Go does not have a builtin "cast" like this, but you can write a function to do it.

You may use reflection to convert a slice of any type to []any:

func unpackArray(s any) []any {
	v := reflect.ValueOf(s)
	r := make([]any, v.Len())
	for i := 0; i &lt; v.Len(); i++ {
		r[i] = v.Index(i).Interface()
	}
	return r
}

You can also use generics in Go 1.18 or later:

func unpackArray[S ~[]E, E any](s S) []any {
	r := make([]any, len(s))
	for i, e := range s {
		r[i] = e
	}
	return r
}

Both versions of these functions work as requested in the question:

myArr1 := []string {&quot;Hey&quot;}
myArr2 := []int {60}
unpackArray(myArr1)
unpackArray(myArr2)

Notes:

  • Go does not have "cast" like some other languages. Go has the somewhat related type assertion and conversion features.
  • The expression arr.([]any) is a type assertion. The expression asserts that the concrete value in the interface arr has type []any. The expression does not do any conversion.
  • The code in the question uses slices , not arrays as written in the title.

答案2

得分: 1

这是要翻译的内容:

直接这样做是不可能的,因为它们不是同一件事。


anyinterface{} 是相同的,每个 interface{} 都是两个指针(第一个是“元数据”/“类型信息”,第二个是指向原始数据的指针)。

如果你有 []uint{60, 42},你有一个切片,每个元素占用8个字节(考虑64位)。所以,如果你强制将其变为 []any,每个元素现在占用16个字节,这会破坏一切。你可以使用 unsafe 来实现这一点

唯一的“转换”方式是复制信息,所以你可以创建一个新的 []any 切片,然后将每个值追加到这个新切片中。


一个复制的示例是:

// 你可以编辑这段代码!

package main

func unpackArray[T any](arr any) (r []any) {
	o := arr.([]T)
	r = make([]any, len(o))

	for i, v := range o {
		r[i] = any(v)
	}

	return r
}

func main() {
	myArr1 := []string{"Hey"}
	myArr2 := []int{60}
	unpackArray[string](myArr1)
	unpackArray[int](myArr2)
}

然而,这并没有太多意义,因为你可以以另一种方式使用泛型。

英文:

It's not possible to do that directly, because it's not the same thing.


any is the same of interface{} and each interface{} is two-pointers (the first one is the "metadata"/"type-information" and the second one the pointer to the original data).

If you have []uint{60, 42} you have one slice that each element is 8-byte (considering 64bits). So, if you force it to be []any, each element now take 16 bytes, that breaks everything. You can do it using unsafe.

The only way to "cast" is copying the information, so, you can create a new slice of []any and then append each value into that new slice.


One example of copying is:

// You can edit this code!

package main

func unpackArray[T any](arr any) (r []any) {
	o := arr.([]T)
	r = make([]any, len(o))

	for i, v := range o {
		r[i] = any(v)
	}

	return r
}

func main() {
	myArr1 := []string{&quot;Hey&quot;}
	myArr2 := []int{60}
	unpackArray[string](myArr1)
	unpackArray[int](myArr2)
}

However, that doesn't make so much sense, since you can use generics in another way.

huangapple
  • 本文由 发表于 2022年7月19日 07:16:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/73029557.html
匿名

发表评论

匿名网友

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

确定