删除slice元素并重新初始化slice [关闭]

What is the correct way to remove an item from a slice in GO?

Also, what is the correct way to reinitialize a slice i.e. completely empty it but still keep it?

The answer is manyfold:

  1. You must realize that there is no slice without backing array and if you talk about a slice you always have to think about the backing array too. Musing about this a bit leads to...
  2. The second part of the question "reinitialize a slice i.e. completely empty it but still keep it" is very unclear. Do not think about slices in this way. a = a[:0] reslices a to zero length while keeping the backing array.
  3. For everything else: Have a look at the "official" Slice Tricks https://code.google.com/p/go-wiki/wiki/SliceTricks

I believe you are misunderstanding the nature of a slice. A slice is like an ArrayList in Java. It is backed by a regular array and grows/shrinks on demand. Operations on a slice have the same performance characteristic as those you would expect on an ArrayList.

Your question(s) would make more sense if slices were the LinkedList equivalent. For that, look up Package list.

Nevertheless, here's how to do this. Most comes directly from SliceTricks, but I think it's good practice on SO to not refer to links and provide the answer right here.

Way to remove an item from a slice

This is something that you can do in any programming language, in O(1) time, if you don't care about order. If you care about order, this is not going to work.

The idea is to overwrite the item you want to remove with the last item in the slice, then reduce the size of the slice by one.

arr := []string{ "allo", "hello", "bye", "chao" }

// delete "bye"
deleteIdx := 2 
lastIdx := len(arr) - 1

// arr = { "allo", "hello", "chao", "chao" }
arr[deleteIdx] = arr[lastIdx]

// arr = { "allo", "hello", "chao" } ... "chao" 
arr = arr[:lastIdx - 1]

You can do that in a single step (SliceTricks):

arr[deleteIdx], arr = arr[len(arr)-1], arr[:len(arr) - 1]

However, like mentionned in the SliceTricks article, some type of values will not be garbage collected if you don't nil them, as the backing array behind the slice still holds a reference to them. The solution is to nil them while doing the operation.

arr[len(arr)-1], arr[deleteIdx], arr = nil, arr[len(arr)-1], arr[:len(arr)-1]
//  ^ Setting the deleted index to nil ^

This is all, of course, if you don't care about preserving order. If you do care, you will need to copy everything after deleteIdx starting over deleteIdx, which is O(n). If you find yourself doing this, think if there isn't a better datastructure for your needs.

// Copy everything from [deleteIdx+1 .. n) onto [deleteIdx .. )
copy(arr[deleteIdx:], arr[deleteIdx+1:])
// arr[n - 1] and arr[n] have the same value (n = len(arr) - 1)
arr[len(arr)-1] = nil
// re-slice to reference only the n-1 elements
arr = arr[:len(arr)-1]

Way to reinitialize a slice i.e. completely empty it but keep it

You can reinitialize a slice by re-slicing all its items out

// Keep everything from [0 .. 0), which means keep nothing
arr = arr[:0]

But there's a problem in doing this : as stated above, the backing array of the slice will still reference to the original items that were in the slice. What you should do instead is create a new slice and let this one be garbage collected.