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.)
EDIT: After recieving a wonderful answer from Stephanie using reflection, I took some inspiration from her to make a function to convert an ambiguous map type into type map[any]any. I am posting it here in case it helps anyone in the future.
package main
import (
"fmt"
"reflect"
)
func unpackMap(s any) map[any]any {
v := reflect.ValueOf(s)
m := make(map[any]any, v.Len())
for _, k := range v.MapKeys() {
m[k] = v.MapIndex(k)
}
return m
}
func main() {
myArr1 := map[string]string {"Hoy":"Hey", "Bay":"Boy"}
myArr2 := map[int]int {40:60, 60:80}
unpackMap(myArr1) // returns map[any]any of myArr1
unpackMap(myArr2) // returns map[any]any of myArr2
}
CodePudding user response:
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 interfacearr
has type[]any
. The expression does not do any conversion. - The code in the question uses slices , not arrays as written in the title.
CodePudding user response:
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.