Copying slices

September 3, 2024

Appending to and copying slices

The function copy copies slice elements from a source src to a destination dst and returns the number of elements copied. The core types of both arguments must be slices with identical element type. The number of elements copied is the minimum of len(src) and len(dst). As a special case, if the destination’s core type is []byte, copy also accepts a source argument with core type bytestring. This form copies the bytes from the byte slice or string into the byte slice.

copy(dst, src []T) int
copy(dst []byte, src string) int

Examples:

var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var s = make([]int, 6)
var b = make([]byte, 5)
n1 := copy(s, a[0:])            // n1 == 6, s is []int{0, 1, 2, 3, 4, 5}
n2 := copy(s, s[2:])            // n2 == 4, s is []int{2, 3, 4, 5, 4, 5}
n3 := copy(b, "Hello, World!")  // n3 == 5, b is []byte("Hello")

There’s not a whole lot to elaborate on here. copy is pretty straight forward, and I think the spec explains it pretty well.

I suppose one topic worth addressing, though, would be: When should you use copy?

As discussed yesterday, there are times when sharing a slice with different parts of code can lead to surprising results. This would be one example of a time that a copy makes good sense.

More generally, just remember that any time you pass a slice to a function, or return one from a function, the recipient may do things to that slice that affect the backing array. If you rely on that backing array not being mutated, you probably want to do a copy.

Here’s an example I see frequently when working with constants, where a copy might make sense:

package animals

type Animal string

const (
	AnimalDog  = "dog"
	AnimalCat  = "cat"
	AnimalBird = "bird"
)

var AllAnimals = []Animal{AnimalDog, AnimalCat, AnimalBird}

There’s room for some sublte abuse in this simple code. Anyone who imports this code could modify AllAnimals.

import "animals"

func init() {
	animals.AllAnimals = append(animals.AllAnimals, "Dinosaur")
}

What’s the solution? Rather than exporting the slice variable directly, create an accessor function:

var allAnimals = []Animal{AnimalDog, AnimalCat, AnimalBird}

func() AllAnimals() []Animal {
	return allAnimal
}

Although this doesn’t quite solve the problem, either:

list := AllAnimals() // list = [dog, cat, bird]
list[1] = "cow"      // list = [dog, cow, bird], but allAnimals also = [dog, cow, bird]

The solution is to return a copy of the authoritative slice:

func() AllAnimals() []Animal {
	c := make([]Animal, len(allAnimals))
	copy(c, allAnimals)
	return c
}

Or a shorter alternative, if you’re using Go 1.21 or newer:

func() AllAnimals() []Animal {
  return slices.Clone(allAnimals)
}

Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Context key type: Final recommendation

First, a correction! An astute reader pointed out that I made a small mistake in my post on June, 10, with regard to string context keys. My code example showed: type contextKey string const ( KeyUserID = "user_id" KeyTransactionID = "transaction_id" KeyMessageID = "message_id" ) But it should have been: type contextKey string const ( KeyUserID contextKey = "user_id" KeyTransactionID contextKey = "transaction_id" KeyMessageID contextKey = "message_id" ) This is a nasty kind of bug, because the code will continue to work as expected—just without any protection from key collisions!


Struct context keys

First off, an apology for being rather unreliable with my “daily” emails. I’m in the middle of some traveling (was in the UK and Netherlands last week, and will be on a US road trip starting tomorrow), so I’m writing when I have a spare moment, which isn’t that often. I’ve been talking about finding the ideal type for a context key. So far I’ve looked at empty structs (e.g. struct{}), integers, and strings.


String context keys

By now we’ve looked at empty structs (struct{}), and integers as possible context key types. Today, let’s consider string context keys. type contextKey string const ( KeyUserID contextKey = "user_id" KeyTransactionID contextKey = "transaction_id" KeyMessageID contextKey = "message_id" ) How does this stack up against our 5 criteria? Must be comparable. ✅ Check. Use minimal memory. ✅ Using a string will typically use a bit more memory than an integer (typically 32 bytes vs 16), but still quite minimal.

Get daily content like this in your inbox!

Subscribe