Go语言多重赋值的原子性疑问:从开发者视角解析
Great question! Let's unpack this clearly, since the Go spec's wording can feel a bit abstract at first.
First, let's clarify what we mean by "atomicity" here—from a developer's perspective, you're asking if operations like a, b = b, a happen as an indivisible unit, without intermediate states messing things up. The short answer is: in a single goroutine, yes, this behaves like an atomic operation for logical purposes. In concurrent scenarios without synchronization? No.
Let's break down the Go spec's two-phase assignment rule you mentioned:
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.
What this means in practice
Phase 1: All values are calculated first
Fora, b = b, a, Go will first evaluate the right-hand side expressions: it grabs the current value ofband the current value ofa, storing these temporary values somewhere. It also resolves any left-hand side expressions (like if you hads[i], s[j] = s[j], s[i], it would calculate the indicesiandjfirst).Crucially, none of the left-hand variables are modified during this phase. The values used for the assignment are frozen at the start of the operation.
Phase 2: Assignments happen left-to-right
Once all values are ready, Go assigns the first temporary value (originalb) toa, then the second temporary value (originala) tob.In a single goroutine, you'll never observe an intermediate state where
ahas been updated butbhasn't—because your code runs sequentially, and the assignment steps are completed before any subsequent lines execute. This is whya, b = b, aworks perfectly for swapping values in your Playground tests.
The catch: Concurrent goroutines
If other goroutines are accessing a and b without synchronization (like mutexes, channels, or atomic operations), things get tricky. The left-to-right assignment in Phase 2 is not a hardware-level atomic operation. Another goroutine could potentially see a updated to the new value while b still holds the old one (or vice versa), depending on how the compiler schedules instructions.
So for concurrent access, you still need to use proper synchronization primitives—multiplexed assignment alone won't make the operation atomic in a thread-safe way.
Example to confirm
Let's say we have:
a := 1 b := 2 a, b = b, a
During Phase 1, Go captures b=2 and a=1. Then Phase 2 sets a=2, then b=1. There's no way b would end up as 2 here—because the value assigned to b was captured before a was modified.
内容的提问来源于stack exchange,提问作者Vojtech Kane

