1

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

2 Answers 2

6

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
}

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

myArr1 := []string {"Hey"}
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.
Sign up to request clarification or add additional context in comments.

Comments

2

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.

1 Comment

Your code worked exactly as described and was very useful, but, since @stephanie gave an answer that requires less on the user-end, I am marking hers as correct. Regardless, thank you for the help!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.