I am attempting to insert an element into an array at a particular index. To do this I split the initial array in two, creating two slices. The "before" slice is the array up to, but excluding, the index. The "after" slice contains the index and the remainder of the array. I then used append to add my new value to the end of the "before" slice and appended the contents of the "after" slice to that.
My first attempt failed but I have since fixed it after a lot of reading. I have reproduced my issue in the Go playground alongside the working version. I'd really like to better understand slices. Can anyone help to explain what's going on?
https://play.golang.org/p/SicOVEclDf
评论:
weberc2:
goomba_gibbon:Your second example doesn't work as you expect because
b
andb[:i]
have the same backing array (they both have a capacity of 4 elements, starting at the same place in memory). The only difference is thatb[:i]
has a length of two elements. When you append tob[:i]
, it grows the length by 1 and adds the new element in that position; however, this modifies the value stored in b[i], which is also the first element of b[i:]. So byappend(b[i:], 3)
, you are settingb[i]=3
, which modifies the first element ofb[i:]
before you append it back onto the slice returned byappend(b[i:], 3)
.The first example works because it creates a new temporary slice backed by a new array1 via
[]int{3}
, and then copiesb[i:]
onto the end of it, so we have a new slice in memory that looks like{3, b[i], b[i+1], etc}
. We then copy that ontob[:i]
, overwriting the old contents with the new, correct contents.Here's a good article on the mechanics of append: https://blog.golang.org/slices
1: The extra allocation can be expensive in a tight loop; the trick to avoid this allocation is:
// extend the *length* of the array by one; this will // allocate a larger backing array, but only if necessary s = append(s, 0) // shift the right-hand-side over one element, creating a // 1-element-wide gap between the left/right sides of the // insert copy(s[i+1:], s[i:]) // write the inserted element into the gap s[i] = x
weberc2:Perfect. Thank you so much for the detailed answer! This makes a lot of sense. I understood that slices were backed by an array but couldn't figure it out.
I think the piece I had missed was that
append(b[i:], 3)
was actually modifying the underlying array ofb
, not allocating a new one. I think that makes sense.
goomba_gibbon:No worries. I'm happy to help. This tripped me up in exactly the same way. The good news is that this should be the last conceptual speed-bump you hit--your concept of slices should now be more or less complete. :)
plaverde:Well it's on reddit now for posterity. Thanks again!
AmduX:Here is a cleaner solution: https://play.golang.org/p/FdrGL1JHV8
goomba_gibbon:Have a look at: https://github.com/golang/go/wiki/SliceTricks
Awesome tips and tricks, helped me a lot.
msgtonaveen:Thanks. I had found this already. The tricks are nice but i want to understand what's going on.
goomba_gibbon:I have wrote a detail tutorial on arrays and slices https://golangbot.com/arrays-and-slices/. It will help you understand how arrays and slices work.
It was a great read. Thanks!
