Understanding Golang multiple assignments

Personal homepage

Multiple assignments of Golang can be used for value exchange operations

The two values can be easily exchanged as follows:

a, b = b, a

The four values can also be exchanged as follows

a, b, c, d = b, c, a, d

So how is this exchange bottom implemented?
Let's do an experiment and look at the assembly code of this four value exchange golang code

func main(){
    a := 1
    b := 2
    c := 3
    d := 4
    a, b, c, d = b, c, a, d
}
$>dlv debug main.go
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x454b6a for main.main() ~/pathToProject/main.go:3
(dlv) r
Process restarted with PID 26528
(dlv) c
> main.main() ~/pathToProject/main.go:3 (hits goroutine(1):1 total:1) (PC: 0x454b6a)
     1: package main
     2:
=>   3: func main() {
     4:         a := 1
     5:         b := 2
     6:         c := 3
     7:         d := 4
(dlv) disassemble
TEXT main.main(SB) D:/Users/polar/go/src/mylab/main.go
        main.go:3       0x454b50        65488b0c2528000000      mov rcx, qword ptr gs:[0x28]
        main.go:3       0x454b59        488b8900000000          mov rcx, qword ptr [rcx]
        main.go:3       0x454b60        483b6110                cmp rsp, qword ptr [rcx+0x10]
        main.go:3       0x454b64        0f8619020000            jbe 0x454d83
=>      main.go:3       0x454b6a*       4883ec50                sub rsp, 0x50
        main.go:3       0x454b6e        48896c2448              mov qword ptr [rsp+0x48], rbp
        main.go:3       0x454b73        488d6c2448              lea rbp, ptr [rsp+0x48]
        main.go:4       0x454b78        48c744242801000000      mov qword ptr [rsp+0x28], 0x1  // a := 1
        main.go:5       0x454b81        48c744242002000000      mov qword ptr [rsp+0x20], 0x2  // b := 2
        main.go:6       0x454b8a        48c744241803000000      mov qword ptr [rsp+0x18], 0x3  // c := 3
        main.go:7       0x454b93        48c744241004000000      mov qword ptr [rsp+0x10], 0x4  // d := 4
        main.go:9       0x454b9c        488b442428              mov rax, qword ptr [rsp+0x28]
        main.go:9       0x454ba1        4889442440              mov qword ptr [rsp+0x40], rax  // temp = a
        main.go:9       0x454ba6        488b442420              mov rax, qword ptr [rsp+0x20]
        main.go:9       0x454bab        4889442428              mov qword ptr [rsp+0x28], rax  // a = b
        main.go:9       0x454bb0        488b442418              mov rax, qword ptr [rsp+0x18]
        main.go:9       0x454bb5        4889442420              mov qword ptr [rsp+0x20], rax  // b = c
        main.go:9       0x454bba        488b442410              mov rax, qword ptr [rsp+0x10]
        main.go:9       0x454bbf        4889442418              mov qword ptr [rsp+0x18], rax  // c = d
        main.go:9       0x454bc4        488b442440              mov rax, qword ptr [rsp+0x40]
        main.go:9       0x454bc9        4889442410              mov qword ptr [rsp+0x10], rax  // d = temp

It's easy to understand that the compiler helps us create a temporary variable temp on the stack, and then exchange the values of other variables in order.

So what happens in this situation?

a := 1
b := 2
a, b, a = b, a, b

What are the final values of a and b?

Take a look at the assembly code

main.go:5   0x454b9b 48c744241801000000   mov qword ptr [rsp+0x18], 0x1  // a:=1
main.go:6   0x454ba4 48c744241002000000   mov qword ptr [rsp+0x10], 0x2  // b:=2
main.go:7   0x454bad 488b442418           mov rax, qword ptr [rsp+0x18]
main.go:7   0x454bb2 4889442428           mov qword ptr [rsp+0x28], rax  // aTemp := a
main.go:7   0x454bb7 488b442410           mov rax, qword ptr [rsp+0x10]
main.go:7   0x454bbc 4889442420           mov qword ptr [rsp+0x20], rax  // bTemp := b
main.go:7   0x454bc1 488b442410           mov rax, qword ptr [rsp+0x10]
main.go:7   0x454bc6 4889442418           mov qword ptr [rsp+0x18], rax  // a = b
main.go:7   0x454bcb 488b442428           mov rax, qword ptr [rsp+0x28]
main.go:7   0x454bd0 4889442410           mov qword ptr [rsp+0x10], rax  // b = aTemp
main.go:7   0x454bd5 488b442420           mov rax, qword ptr [rsp+0x20]
main.go:7   0x454bda 4889442418           mov qword ptr [rsp+0x18], rax  // a = bTemp

Amount to

aTemp = a
bTemp = b
a, b, a = bTemp, aTemp, bTemp

Here, the principle of two value exchange operation is to store the values of two assigned variables in temporary variables, and then use temporary variables to assign values. So the order of assignment in this example has no effect on the result, and the result is still a = 2, b = 1.

No longer need to write the exchange function and inline like C, which is equivalent to leaving the dirty work to the compiler.

Welcome to reprint, please indicate the source~
Author's homepage

Tags: Go

Posted on Sat, 09 Nov 2019 14:54:37 -0500 by php1