How to convert slice to fixed size array?
45,090
Solution 1
Edit: as of Go 1.17+, you may be able to use new support for slice-to-array conversions, https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer:
s := make([]byte, 2, 4)
s0 := (*[0]byte)(s) // s0 != nil
s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1]
s2 := (*[2]byte)(s) // &s2[0] == &s[0]
s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s)
Previous answer for Go 1.16 and below:
You need to use copy
:
slice := []byte("abcdefgh")
var arr [4]byte
copy(arr[:], slice[:4])
fmt.Println(arr)
As Aedolon notes you can also just use
copy(arr[:], slice)
as copy will always only copy the minimum of len(src)
and len(dst)
bytes.
Solution 2
I found a way to solve the problem without allocating any more space - to define a new struct with the same construction as slice and receive the unsafe.Pointer.
type MySlice struct {
Array unsafe.Pointer
cap int
len int
}
func main(){
a := []byte{1, 2, 3, 4}
fmt.Printf("a before %v, %p\n", a, &a)
b := (*MySlice)(unsafe.Pointer(&a))
c := (*[4]byte)(b.Array)
fmt.Printf("c before %v, %T, %p\n", *c, *c, c)
a[1] = 5
fmt.Printf("c after %v, %p\n", *c, c)
fmt.Printf("a after %v, %p\n", a, &a)
}
the result shows as follows:
Related videos on Youtube
Comments
-
thi gg almost 2 years
I want to convert a fixed size array from a slice:
func gen(bricks []Brick) { if len(bricks) == 16 { if check(Sculpture{bricks}) { var b [16]Brick = bricks[0:16]; } } }
But this results in:
cannot use bricks[0:16] (type []Brick) as type [16]Brick in assignment
How to convert a slice into a fixed size array?
-
LemurFromTheId almost 9 yearsThis is correct, but a small addition: you don't need
copy(arr[:], slice[:4])
,copy(arr[:], slice)
is enough.copy
automatically limits itself to the smaller of the given slices. -
Stephan Dollberg almost 9 years@Aedolon Thanks for the hint, added it to the answer.
-
Shudipta Sharma over 4 yearsnice answer, really.
-
Flimzy over 3 yearsThis example is very easy to break. See here: play.golang.org/p/iSq4Q9XrRQv
-
Flimzy over 3 yearsAlso, don't paste images of text.
-
JimB over 3 yearsIf you really need to do this, don't use your own slice header, just convert the data directly: play.golang.org/p/3oNob6k5ynx
-
Yiheng over 3 years@JimB thanks for that. But if you change any element of i, x's value will not change. It seems like a deep copy.
-
JimB over 3 years@Yiheng: yes, because arrays are values in the first place, so assignment itself is a copy. If you don't want a copy, you need to use a pointer, but in that case, why not just use a slice in the first place? play.golang.org/p/kF3_46UDbJN
-
Yiheng over 3 years@JimB Since I need to use a slice as the key of a map, it is the easiest way to do so in my understand. However, your code is better than mine. Thanks for that, and I learned a lot.
-
Flimzy over 3 yearsCan you just use byte arrays from the beginning, so no conversion is necessary?
-
Yiheng over 3 years@Flimzy I really can't, since all data are from protobuf.
-
Flimzy over 3 yearsI'm not intimately familiar with that level of detail, but AFAIK, you can unmarshal a pb message into an arbitrary type, so should be able to unmarshal into byte arrays instead of byte slices. If nothing else, you can probably set the target array to be backed by an explicit array.
-
Chris Smowton over 2 yearsNote as of Golang 1.17 you can use tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
-
Stephan Dollberg over 2 years@ChrisSmowton please either edit that to my answer or post a new one as if there is a newer way then that should be in a proper answer and not just a comment.