This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 2 years ago.
I have value [token code id_token] from map, value of map type []interface{}
resp := result["response_types"]
resp is type []interface{}.
i need to convert it to: clientobj.ResponseTypes
type client struct{
ResponseTypes sqlxx.StringSlicePipeDelimiter `json:"response_types" db:"response_types"`
}
in package sqlxx
package sqlxx
type StringSlicePipeDelimiter []string
is there is to convert it?
To convert a []inteface{} to []string, you just iterate over the slice and use type assertions:
// given resp is []interface{}
// using make and len of resp for capacity to allocate the memory in one go
// instead of having the runtime reallocate memory several times when calling append
str := make([]string, 0, len(resp))
for _, v := range resp {
if s, ok := v.(string); ok {
str = append(str, s)
}
}
The real question here is how you end up with a variable of type []interface{} in the first place. Is there no way for you to avoid it? Looking at the StringSlicePipeDelimiter type itself, it has the Scan method (part of the interface required to scan values from the database into the type) right here, so I can't help but wonder why you're using an intermittent variable of type []interface{}
Related
This question already has an answer here:
Gomock cannot use type map[string]*mockFoo as map[string]foo
(1 answer)
Closed 4 months ago.
In my function I was receiving an argument that contained a map for which the value's type was any. I would have thought that any type could therefore be sent, but I got the following error when I tired to use map[string]CustomStruct:
cannot use mapToPrint (variable of type map[string]CustomStruct) as type map[string]any in argument to printMap.
If I create the map with type's value any, everything works, including the assignment of CustomStruct to map values.
Here is a reproducing example:
type CustomStruct struct {
name string
}
func main() {
mapToPrint := make(map[string]CustomStruct, 0)
mapToPrint["a"] = CustomStruct{"a"}
mapToPrint["b"] = CustomStruct{"b"}
printMap(mapToPrint)
}
func printMap(mapToPrint map[string]any) {
for key, value := range mapToPrint {
fmt.Println(key, value)
}
}
go.dev
As the go FAQ says here:
It is disallowed by the language specification because the two types do not have the same representation in memory.
As the FAQ suggests, simply copy the data from your map into a map with value type any, and send it like so to the function:
printableMap := make(map[string]any, len(mapToPrint))
for key, value := range mapToPrint {
printableMap[key] = value
}
This question already has answers here:
Type converting slices of interfaces
(9 answers)
Cannot convert []string to []interface {}
(7 answers)
Cannot use args (type []string) as type []interface {} [duplicate]
(1 answer)
slice of struct != slice of interface it implements?
(6 answers)
Closed 4 months ago.
I'm slightly confused about the behavior of the unpack/spread operator when trying to append into a slice of empty interfaces (i.e. []interface{}) from an slice of a custom type. I expected it to work since the interface{} can hold any type, but I'm currently receiving errors when trying to do this operation.
The following snippet illustrates the issue:
package main
import (
"fmt"
)
type CustomType struct {
value int
}
func main() {
data := []interface{}{}
values := []CustomType{
{value: 0},
{value: 1},
}
// This does not compile:
// data = append(data, values...)
// But this works fine
data = append(data, values[0])
for _, value := range data {
fmt.Printf("Value: %v\n", value)
}
}
Go playground with the snippet above
I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type. When I append the values one by one, then compiler is OK with the operation.
Why is unpacking the values slice not allowed in this situation?
Obviously, the code data = append(data, values...) could be compiled error cannot use values (variable of type []CustomType) as type []interface{} in argument to append
Per faq Can I convert a []T to an []interface{}?
Not directly. It is disallowed by the language specification because the two types do not have the same representation in memory. It is necessary to copy the elements individually to the destination slice. This example converts a slice of int to a slice of interface{}:
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
For your question
I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type.
The difference between the element type CustomType and interface
type CustomType represented in memory like value
type interface{} represented in memory
pointer to type CustomType
value
They have different representations in memory.
Besides that, converting a []CustomType to an []interface{} is O(n) time because each value of the slice must be converted to an interface{}. It could be one complex operation.
This question already has answers here:
Type converting slices of interfaces
(9 answers)
In Go, how do I pass a slice of interface to something that expects slice of a different compatible interface? [duplicate]
(1 answer)
How can I cast from []interface{} to []int? [duplicate]
(1 answer)
Cannot use args (type []string) as type []interface {} [duplicate]
(1 answer)
Convert map[interface {}]interface {} to map[string]string
(3 answers)
Closed 7 months ago.
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
}
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.
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.
This question already has answers here:
How to convert a slice of one numeric type to another type
(2 answers)
Closed 3 years ago.
I want to convert a slice of []int64 to []uint64, what is the most efficient and elegant way? I just know the below way:
func convert(userIDs ...int64) []uint64 {
uIDs := make([]uint64, len(userIDs))
for index, uID := range userIDs {
uIDs[index] = uint64(uID)
}
fmt.Printf("%T, %v\n", uIDs, uIDs)
return uIDs
}
Without resorting to unsafe you cant avoid a loop:
b := make([]uint64, len(a))
for i, v := range a {
b[i] = uint64(v)
}
For further info/examples see this question or this one. If you really want to use unsafe then b := *(*[]uint64)(unsafe.Pointer(&a)) will work (but I would not recommend using this unless you have a compelling reason to do so).
There's only one way to convert one slice to another, as Birits have answered.
Unless you're looking for cast methods:
1) unsafe.Pointer cast *(*[]uint64)(unsafe.Pointer(&int64_slice))
2) reimport with edited singature using linkname pragma:
//go:linkname convert convert.Slice
func convert(userIDs []int64) []int64 {
return userIDs
}
//go:linkname ConvertSliceInt64ToUInt64 convert.Slice
func ConvertSliceInt64ToUInt64(userIDs ...int64) []uint64
https://play.golang.org/p/8b-yVL_Ps-c
This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 4 months ago.
I need an abstracted slice that contains multiple types. The most simplified code is this:
package main
import "fmt"
type A interface{}
type X string
func main() {
sliceA := make([]A, 0, 0)
sliceX := []X{"x1", "x2"}
var appendedSlice []A
appendedSlice = append(sliceA, sliceX[0], sliceX[1]) // (1) works
appendedSlice = append(sliceA, sliceX...) // (2) doesn't work
fmt.Println(appendedSlice)
}
In my real program, the interface A defines some functions, and X and also other types implement it.
Line (2) raises an error cannot use sliceX (type []X) as type []A in append.
I thought (2) is a syntax sugar for (1), but I'm probably missing something... Do I have to always add an element X into slice A one by one?
Thank you guys in advance!
The problem is that interface{} and string are two different types.
To convert a slice from string to interface{} you will have to do it in one of the following ways:
create sliceA and initialize its size to sliceX length
sliceA := make([]A, len(sliceX))
for ix, item := range sliceX {
sliceA[ix] = item
}
dynamically append sliceX items to appendedSlice
var appendedSlice []A
for ix := range sliceX {
appendedSlice = append(appendedSlice, sliceX[ix])
}
Please read more here
Convert []string to []interface{}