Today, I was sliced by Go’s slices. Actually, by Go’s variadics. Question: what does this snippet print?
func main() {
nums := []int{1, 2, 3}
PrintSquares(nums...) // variadic expansion
fmt.Printf("2 %v\n", nums)
}
func PrintSquares(nums ...int) {
for i, n := range nums {
nums[i] = n * n
}
fmt.Printf("1 %v\n", nums)
}
Answer (Playground):
1 [1 4 9]
2 [1 4 9]
ðŸ«
Meaning, in Go, when you use a slice for variadic expansion (s...),
and you use a variadic parameter to capture said slice (paramSlice ...int),
they are the same1 slice, and mutating one will mutate the other.
In Python, you actually can’t do that because *args is always a tuple:
def check(*args):
args[1] = "hi zev" # TypeError: 'tuple' object does not support item assignment
l = [1, 2, 3]
check(*l)
print(l)
So the assignment fails, but even with **kwargs:
def check(**kwargs):
kwargs["1"] = "hi zev"
d = {"1": None}
check(**d)
assert d["1"] is None, "Sanity prevails! 😌"
We get a new dictionary in the callee, and sanity prevails.
And, TBH, I’ve been putting up with Go’s… peculiarities for a while now, but every now and then there’s something like this, where I feel like Go wants me to die an early death from high blood pressure.
Which it probably doesn’t. But I can’t shake that feeling.
$ /usr/bin/time go build
49.82 real 59.75 user 27.26 sys
$
Why don’t you print anything, Go? WHY?

why? 😔
–
If you liked this, you might also like The story of the craziest __init__ I’ve ever seen.
They are almost the same: they share the same underlying array. You do get a copy of the little
(ptr, len, capacity)struct which is what a slice is.
If you reassign the variable, e.gnums = append(nums, 16), that’s a differentstorycan of worms entirely. ↩︎