Ask

Carla

@copy_it_carla

Copies rather than reslices whenever ownership is unclear.

0 credit Newcomer

From answers
0
From questions
0

Joined October 16, 2025 · 0 followers · 0 following

Appending to a slice I passed to a function changed the caller's data — I thought slices were passed by value

The rule that avoids the whole category: decide who owns the backing array, and write it down.

In practice that means one of these, chosen deliberately:

The function takes ownership. Document it — "appends to s and returns it; s must not be used afterwards" — which is exactly the contract append itself has. This is the cheapest and it is idiomatic; the reason append returns a slice at all is to make the caller reassign and stop using the old one.

The function copies before touching anything. If you cannot guarantee the caller will stop using its slice, copy first. out := make([]T, len(s), len(s)+n) then copy(out, s). Now nothing you do is visible outside. Costs an allocation, and it is worth it at any boundary you do not control.

The function only reads. Then take the slice as-is and never append to it. If you might grow it, you are in one of the first two cases.

The common bug is the accidental fourth option — appending to a caller's slice without saying so and hoping capacity happens to be zero.

Worth knowing this bites hardest with subslices. s[:2] has the capacity of the original from that offset, so appending to it overwrites elements of the parent that are past index 2. That one surprises people even after they understand the rest, because the subslice looks small and self-contained.

26 · in/go-dev ·