Assignment order

May 2, 2024

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)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Defer execution order

Let’s talk about some of the nuance surrounding defer that’s often lost, or simply forgotten. Defer statements … Each time a “defer” statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller.


Execution of a select statement

I’m looking for a new client or two. Could your team use some expert Go help? Reach out, and let’s talk! Select statements … Execution of a “select” statement proceeds in several steps: For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the “select” statement. The result is a set of channels to receive from or send to, and the corresponding values to send.


Tuple assignments

Yesterday (as well as in earlier emails) I mentioned multiple-assignments in a single statement. Today we see how they’re defined to work. As such, there’s not really an new material here, but we’ll cover it just the same. Assignment statements … A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion.

Get daily content like this in your inbox!

Subscribe