Reputation: 156434
According to the "Assignments" section of the Go Language Spec:
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.
While playing with slices and attempting to implement a simple "delete" (or "splice") operation I see the following confusing behavior (Go Playground):
xs := []int{1, 2, 3, 4, 5}
x := xs[2]
xs = append(xs[:2], xs[3:]...)
fmt.Printf("OK: x=%d, xs=%#v\n", x, xs)
ys := []int{1, 2, 3, 4, 5}
y, ys := ys[2], append(ys[:2], ys[3:]...)
fmt.Printf("??: y=%d, ys=%#v\n", y, ys)
// OK: x=3, xs=[]int{1, 2, 4, 5}
// ??: y=4, ys=[]int{1, 2, 4, 5}
Why do the separate assignments to "x" and "xs" work as expected in the first example but the multi-assignment to "y" and "ys" appears to evaluate out of order? Is it related to the implicit define-and-assign combination?
Upvotes: 3
Views: 1720
Reputation: 156434
As noted by @peterSO, according to the "Order of evaluation" section of the spec:
... the order of [function calls] compared to the evaluation and indexing of [index expressions] is not specified.
Which means that, for the example code above, the append(...)
function call happens to occur before the index expression, since the relative order of those operations is not specified.
If you wrap the index expression in a function call then the operations occur in the expected order:
idint := func(x int) int { return x }
zs := []int{1, 2, 3, 4, 5}
z, zs := idint(zs[2]), append(zs[:2], zs[3:]...)
fmt.Printf("OK: z=%d, zs=%#v\n", z, zs)
// OK: z=3, zs=[]int{1, 2, 4, 5}
Upvotes: 0
Reputation: 166588
The Go Programming Language Specification
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.
At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations. Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
For example, in the (function-local) assignment
y[f()], ok = g(h(), i()+x[j()], <-c), k()
the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.
Follow the link (evaluated in the usual order), that you should have included in your quote, to the Order of Evaluation section.
For your example, evaluate the append
function first:
package main
import (
"fmt"
)
func main() {
xs := []int{1, 2, 3, 4, 5}
x := xs[2]
xs = append(xs[:2], xs[3:]...)
fmt.Printf("OK: x=%d, xs=%#v\n", x, xs)
ys := []int{1, 2, 3, 4, 5}
y, ys := ys[2], append(ys[:2], ys[3:]...)
fmt.Printf("OK: y=%d, ys=%#v\n", y, ys)
{
ys := []int{1, 2, 3, 4, 5}
// phase 1
t1 := append(ys[:2], ys[3:]...)
t2 := ys[2]
// phase 2
y = t2
ys = t1
fmt.Printf("OK: y=%d, ys=%#v\n", y, ys)
}
// OK: x=3, xs=[]int{1, 2, 4, 5}
// OK: y=4, ys=[]int{1, 2, 4, 5}
}
Playground: https://play.golang.org/p/n9f0qhZadUr
Output:
OK: x=3, xs=[]int{1, 2, 4, 5}
OK: y=4, ys=[]int{1, 2, 4, 5}
OK: y=4, ys=[]int{1, 2, 4, 5}
Upvotes: 2