We’ve already talked about the order of evaluation in Go. And while that’s perfectly relevant here, it’s only one piece of the puzzle when it comes to ordering with assignment operations:
Assignment statements
…
The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.
a, b = b, a // exchange a and b x := []int{1, 2, 3} i := 0 i, x[i] = 1, 2 // set i = 1, x[0] = 2 i = 0 x[i], i = 2, 1 // set x[0] = 2, i = 1 x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2 (so x[0] == 2 at end) x[1], x[3] = 4, 5 // set x[1] = 4, then panic setting x[3] = 5. type Point struct { x, y int } var p *Point x[2], p.x = 6, 7 // set x[2] = 6, then panic setting p.x = 7 i = 2 x = []int{3, 5, 7} for i, x[i] = range x { // set i, x[2] = 0, x[0] break } // after this loop, i == 0 and x is []int{3, 5, 3}
What’s not explicitly mentiond here, but is relevant, is that function calls on the left-hand side can be part of the relevant index expression and pointer indirection operations that happen first. A trivial example:
x[foo()] = 3 // foo() is called to return the index
A somewhat less intuitive example:
foo()[0] = 3
Is that valid? It can be if foo()
returns a slice of int
values, for example.
Quiz time. Is this valid? Why or why not? Give your best answer before running it.
var i int
func main() {
x := int(3)
foo() = &x
fmt.Println(i)
}
func foo() *int {
return &i
}
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)