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
Related
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 7 days ago.
I have two types AssetClips and Videos that implement the interface call timelineClip.
I wanted to pass a []AssetClips or a []Videos to a function that take as argument a []timelineClip but the compiler was complaining, I don't really understand why. I ended up doing a for loop to convert my []AssetClips and my []Videos to []timelineClip
Is it necessary and is there a more elegant way of doing that?
// myFunctionThatTakesASliceOfTimelineClips(assetClips) is not possible
// myFunctionThatTakesASliceOfTimelineClips(videos) is not possible
var timelineClips []timelineClip
for _, assetClip := range assetClips {
timelineClips = append(timelineClips, assetClip)
}
for _, video := range videos {
timelineClips = append(timelineClips, video)
}
myFunctionThatTakesASliceOfTimelineClips(timelineClips)
It is necessary, and this is an elegant way to do it.
This is necessary because the mechanics of passing a slice of interface is different from the mechanics of passing a slice of structs. Each element of a slice of structs is a copy of the struct itself, whereas the elements of an interface is an interface pointing to an instance of a struct, together with its type.
If you want to avoid copying, you could use a generics for this. In short, you just change signature of
func myFunctionThatTakesASliceOfTimelineClips(timelineClips []timelineClip)
to
func myFunctionThatTakesASliceOfTimelineClips[T timelineClip](timelineClips []T)
As an example:
https://go.dev/play/p/FTj8rMYq9GF
package main
import "fmt"
type Exampler interface {
Example()
}
type A struct{}
type B struct{}
func (a A) Example() {
fmt.Println("it worked")
}
func (b B) Example() {
fmt.Println("it worked")
}
func DoExample[T Exampler](tt []T) {
for _, t := range tt {
t.Example()
}
}
func main() {
aa := []A{{}}
bb := []B{{}}
DoExample(aa)
DoExample(bb)
}
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:
Why a generic can't be assigned to another even if their type arguments can?
(1 answer)
Can I construct a slice of a generic type with different type parameters?
(2 answers)
Go generic container with different runtime types
(1 answer)
Closed 10 months ago.
This post was edited and submitted for review 10 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I want to be able to enforce similarity between two fields of a struct but also have several of these structs in a map or slice.
Here's a simplified example of my problem:
package main
type foo[T any] struct {
f func() T
v T
}
type bar struct {
x []*foo[any]
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[any]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
The compiler complains
./prog.go:13:33: cannot use f (variable of type func() T) as type func() any in struct literal
The funny thing is that this can work if I didn't need to have a function pointer in the struct. See https://go.dev/play/p/qXTmaa9PuVe
So, is there a way for me to turn a T into an any?
I know I could do this with interface{}s and use reflect to enforce what I want, but I'm sure it's possible with only generics.
The context in case there is a way around my problem is that I'm making a flag package. The important structs look like this:
type flag[T any] struct {
value T
parse func(in string) (T, error)
// Other fields removed for simplicity...
}
type FlagSet struct {
// could flag[any] be replaced with a better answer?
flags map[string]*flag[any]
// Other fields removed for simplicity...
}
The question was closed so I have to put the answer to the second part of my question here
could flag[any] be replaced with a better answer?
The answer to the above is yes.
Solution:
Originally I though something like: "a func() fits a func() and an any fits a T so why can't I have a func() T fit a func() any?" Of course the reason is a func() any is not an any and so it cannot hold a func() T.
Instead, you can do the following:
package main
type foo[T any] struct {
f func() T
v T
}
func (f *foo[_]) set() {
f.v = f.f()
}
type anyfoo interface {
set()
}
type bar struct {
x []anyfoo
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[T]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
but also have several of these structs in a map or slice
You cannot do this (in a type safe way). All values of e.g. a slice must have the same element type. If you want to store different ones you have to resort to interface{} and type switch later.
If you use the correct technical term parametric polymorphism instead of "generics" which doesn't explain what is going on you will see why func(T) and func(any) are different, unconvertable types.
So, is there a way for me to turn a T into an any?
No, there was no pre-"generics" way and there is no post-"generics" way. It helps to think of "turn into" as what Go allows: "type conversion" and "assignment". You can assign any variable of type T to a variable of type any.
You might overcome your issue by using an adaptor function (closure):
w := func(a any){ f(a.(T)) }
b.x = append(b.x, &foo[any]{w})
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{}
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{}