简体   繁体   中英

golang: How do you cast an array of unknown type to type []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.)

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 < 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
}

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.

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{"Hey"}
    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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM