After having written probably over 100k lines of Go code, my impression is that Go is simple, but not easy. The language has very few features to learn, but that results in a lot of boilerplate code and there are more than a few footguns burried in the language itself. (My favorite [1])
I find it very hard to write expressive, easy to read code and more often than not I see people using massive switch-case statements and other, hard to maintain patterns instead of abstracting away things because it's so painful to create abstractions. (The Terraform/OpenTofu codebase is absolutely guilty of this btw, there is a reason why it's over 300k lines of code. There is a lot of procedural code in there with plenty of hidden global scope, so getting anything implemented that touches multiple parts typically requires a lot of contortions.)
It's not a bad language by any stretch, but there are things it is good at and things it is not really suited for.
Slices are structures that hold a pointer to the array, a length, and a capacity!
So, when you slice a slice, if you perform an array operation like “append” while there is existing capacity, it will use that array space for the new value.
When the sliced value is assigned to another variable, it’s not a pointer that’s copied, it’s a new slice value (with the old length). So, this new value thinks it has capacity to overwrite that last array value - and it does.
So, that also overwrites the other slice’s last value.
If you append again, though, you get a (new) expanded array. It’s easier to see with more variables as demonstrated here: https://go.dev/play/p/AZR5E5ALnLR
(Sorry for formatting issues in that link, on phone)
It's because slices have underlying arrays which define their capacity (cap(s)).
Both slices start out having the same underlying (bigger) array -so appending to one slice can affect the other one.
In the "bonus" part, though, the appends outgrew the original array, so new underlying arrays were allocated (i.e. the slices stopped sharing the same backing array).
Yes-ish? Slices are this weird construct where they sometimes behave like references and sometimes not. When I read the explanation, it always makes sense, but when using them it doesn't. For me the rule is: don't reuse slices and don't modify them unless you are the "owner" of the slice. Appending to a slice that was returned to you from a function is usually a pretty good way to have a fun afternoon debugging.
I find it very hard to write expressive, easy to read code and more often than not I see people using massive switch-case statements and other, hard to maintain patterns instead of abstracting away things because it's so painful to create abstractions. (The Terraform/OpenTofu codebase is absolutely guilty of this btw, there is a reason why it's over 300k lines of code. There is a lot of procedural code in there with plenty of hidden global scope, so getting anything implemented that touches multiple parts typically requires a lot of contortions.)
It's not a bad language by any stretch, but there are things it is good at and things it is not really suited for.
[1]: [link redacted]