Skip to content
Go Basics: Copy Slices Before Editing Shared Data

Go Basics: Copy Slices Before Editing Shared Data

October 31, 2026

A function that edits a slice can unexpectedly change the caller’s data. Reproduce that aliasing with a small price list, then make ownership explicit before editing.

Prepare a scratch directory

Tested on Linux amd64 with Go 1.26.10. Install Go and make go available on PATH. You also need Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The example uses only the standard library and needs no module or external dependency.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

Run the example

Save this as slice-ownership-demo.go:

package main

import (
	"fmt"
	"slices"
)

func main() {
	prices := []int{10, 20, 30}
	view := prices[:2]
	view[0] = 99
	fmt.Println("Shared:", prices)
	isolated := slices.Clone(prices)
	isolated[1] = 77
	fmt.Println("Original:", prices)
	fmt.Println("Clone:", isolated)
	clipped := prices[:2:2]
	grown := append(clipped, 40)
	grown[0] = 5
	fmt.Println("After append:", prices, grown)
}

Run it:

go run slice-ownership-demo.go

Observed output:

Shared: [99 20 30]
Original: [99 20 30]
Clone: [99 77 30]
After append: [99 20 30] [5 20 40]

Read the result

A slice is a view of an underlying array, so changing view[0] changes prices[0]. slices.Clone allocates separate element storage. The full slice expression limits capacity to two; appending a third element must allocate a new array, which isolates the later edit to grown.

Apply it carefully

Limiting capacity does not isolate edits made before append. Cloning is shallow: if elements contain pointers, maps, or other slices, their referenced data can still be shared. Use this pattern when the elements themselves are values, or explicitly copy the nested mutable data.

The official Go reference documents the behavior used here.

Clean up

Remove the saved source, return to the starting directory, and remove the empty practice directory. go run does not leave an executable here; Go manages its build cache separately.

rm -- slice-ownership-demo.go
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on