Three new books, Go Optimizations 101, Go Details & Tips 101 and Go Generics 101 are published now. It is most cost-effective to buy all of them through this book bundle in the Leanpub book store.

How to clone slices?

The approaches

There are several ways to do the task.

Way 1: use make and copy

	cloned := make(SliceType, len(aSlice))
	copy(cloned, aSlice)

Note:

For the two reasons, thw way is the fastest approach.

The drawbacks of this approach:
  1. If the source slice aSlice is nil, the cloned slice is not nil. Sometimes, this matters.
  2. It is a little verbose (it needs two lines).
  3. It can't be used as a sub-expression in statements.
  4. It needs to import the containing package of type SliceType if SliceType is declared in another package.

Way 2: the more verbose form of way 1

	var cloned SliceType
	if aSlice != nil {
		cloned = make(SliceType, len(aSlice))
		copy(cloned, aSlice)
	}

Excpet for the first drawback of the way 1, the verbose way offers similar benefits and drawbacks to way 1.

Way 3: use make and append

	append(make(SliceType, 0, len(aSlice)), aSlice...)

The approach can be used as a sub-expression in statements.

Note:

The drawbacks of this approach:
  1. For the two reasons, currently, thw way is the slowest way.
  2. If the source slice aSlice is nil, the cloned slice is not nil. Sometimes, this matters.
  3. It needs to import the containing package of type SliceType if SliceType is declared in another package.

Way 4: use append

	append(SliceType(nil), aSlice...) // manner 1
	// or
	append(SliceType{}, aSlice...) // manner 2

Similar to the last one, the approach can be used as a sub-expression in statements.

Note:

The drawbacks of this approach:
  1. For the two reasons, thw way is slower than other ones.
    • for manner 1, if the source slice aSlice is a non-nil blank slice, the cloned slice is nil.
    • for manner 2, if the source slice aSlice is a nil slice, the cloned slice is not nil.
  2. It needs to import the containing package of type SliceType if SliceType is declared in another package.

Way 5: use append cleverly

	append(aSlice[:0:0], aSlice...)

This approach improves on the last one by avoiding the two drawbacks listed above, which means:

This might be the cleanest implementation while still maintaining great performance. It is almost perfect. But it has one (potential tiny) drawback: if the source slice aSlice is a non-nil blank slice, then the cloned slice (also a non-nil blank slice) references the same underlying element memory block as the source slice. This might prevent (or delay) the collection of the element memory block when the source slice become unused.

The tiny drawback can be removed by improving the official Go runtime implementation. But up to now, the improvement has not been made.

Way 6: use slices.Clone (since Go 1.21)

import "slices"

	slices.Clone(aSlice)

The current implementation of slices.Clone simply uses the way 5 approach. So it offers similar benefits and drawbacks to way 5. And it has one more drawback: it needs to import the "slices" stdandard package.

So?

There's no single perfect way to clone slices in Go. Just choose the way that best suits your situation.


(more articles ↡)

The Go 101 project is hosted on Github. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.

If you would like to learn some Go details and facts every serveral days, please follow Go 101's official Twitter account @zigo_101.

Tapir, the author of Go 101, has been on writing the Go 101 series books and maintaining the go101.org website since 2016 July. New contents will be continually added to the book and the website from time to time. Tapir is also an indie game developer. You can also support Go 101 by playing Tapir's games (made for both Android and iPhone/iPad):
Individual donations via PayPal are also welcome.

Articles in this book: