-1

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
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
avid
  • 9
  • 2

2 Answers2

3

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).

Brits
  • 14,829
  • 2
  • 18
  • 31
  • Yes, it's a simple way, I'm just curious about this question, is there any other way to do and how to do it with unsafe? – avid Feb 14 '20 at 03:07
  • Take a look at the first [other question](https://stackoverflow.com/questions/31891493/why-are-you-unable-convert-slice-types) I referenced; that goes into a reasonable amount of detail about using unsafe. – Brits Feb 14 '20 at 03:14
-1

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

Laevus Dexter
  • 472
  • 4
  • 5
  • There's no way that the GC will be unaware of the slices themselves, or the slice headers, and int64 and uint64 are both non-pointer types, so there's no possibility of GC confusion in the payload. Maybe for slices of more complex types, but not here. – hobbs Feb 14 '20 at 04:14
  • @hobbs: slice header has backed pointer to an array which contains the content, which isn't being marked by gc in case of cast, if original data were swept by gc, the casted one will cause "invalid pointer" panic – Laevus Dexter Feb 14 '20 at 04:17
  • @hobbs: https://golang.org/pkg/reflect/#SliceHeader – Laevus Dexter Feb 14 '20 at 04:22
  • You're misunderstanding that 100%. The cast slice *will* be seen by the GC. – hobbs Feb 14 '20 at 04:27
  • @hobbs: hmm, after tests, it seems that you are right, gc is aware of it in all cases except delayed reflect.SliceHeader cast https://play.golang.org/p/LqzZAFvVNgO – Laevus Dexter Feb 14 '20 at 05:28
  • Yes, it's just the `uintptr` in a `reflect.SliceHeader` that doesn't count as a pointer and isn't traversed by the GC (that's somewhat the point of `uintptr`). That doesn't apply to *real* slice headers. – hobbs Feb 14 '20 at 05:46
  • @hobbs: as you can see at the provided playground, it counts as a pointer, and gc is aware of it, as long as a backed array is alive at the moment of the reflect.SliceHeader -> []uint64 cast, in the other words gc starts following a pointer only after cast itself. – Laevus Dexter Feb 14 '20 at 06:03