Skip to content

How to perfectly clone a slice?

Go101 edited this page May 15, 2021 · 19 revisions

Go official wiki lists two ways to clone/copy a slice:

b = make([]T, len(a))
copy(b, a)

and

b = append([]T(nil), a...)

However, both of the two are not perfect.

  • For the first way, the result slice b is not nil even if the source slice a is nil.
  • For the second way, the result slice b is nil even if the source slice a is a non-nil blank slice.

The following code will fix the problems of the above two ways.

b = nil
if a != nil {
	b = make([]T, len(a))
	copy(b, a)
}

The new way is quite verbose. Is there a one-line perfect solution? Yes, the following way is the best slice clone solution according to what I know.

b = append(a[:0:0], a...)

This solution guarantees that b is nil if a is nil and b is not nil if a is no nil. It makes use of the fact that a slice derived from a nil slice is still a nil slice. And the three-index subslice form ensures that the result slice will not share any elements with the source slice.

(Note: The way introduced in this article is not the best solution universally. For some scenarios, the target slice is expected to be nil even if the source slice is a non-nil blank one, to avoid sharing underlying elements.)

(Note 2: There is an imperfection in the perfect clone implementation: the capacity of the result slice might be not the same as the length of the result slice, which leads to the following note 3.)

(Note 3: the append way is a little inefficient in execution than the make+copy way per pure-clone purpose.)

[update]: There is not a perfect way to clone slices in Go actually.

Clone this wiki locally