xmllmx
xmllmx

Reputation: 42379

Is it safe to swap two integers by `a, b = b, a` in golang?

package main

import "fmt"

func main() {
    a := 1
    b := 2

    fmt.Printf("Before Swap: %v %v\n", a, b)
    a, b = b, a
    fmt.Printf(" After Swap: %v %v\n", a, b)
}

The output is:

Before Swap: 1 2  
 After Swap: 2 1

It looks good. I just wonder:

Is it safe to swap two integers by a, b = b, a in golang?

Upvotes: 3

Views: 221

Answers (2)

cuonglm
cuonglm

Reputation: 2816

Yes, it's safe to swap two variables using:

a, b = b, a

The assignment happens in two steps:

  • The right hand side of the assignment is evaluated first.
  • Then the evaluated values will be assigned to the left hand side in left-to-right order.

In other words, a, b = b, a will be rewritten roughly to:

tmpB := b
tmpA := a
a = tmpB
b = tmpA

That's why the assignment is safe.


In fact, the compiler is smart enough to avoid a second temporary variable, so a, b = b, a will be rewritten as:

tmpA := a
a = b
b = tmpA
$ cat x.go 
package p

func f(a, b int) {
    a, b = b, a
}
$ go tool compile -W x.go

before walk f
.   AS2 tc(1) # x.go:4:7
.   AS2-Lhs
.   .   NAME-p.a esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:8
.   .   NAME-p.b esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:11
.   AS2-Rhs
.   .   NAME-p.b esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:11
.   .   NAME-p.a esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:8
after walk f
.   BLOCK # x.go:4:7
.   BLOCK-List
.   .   AS tc(1) # x.go:4:7
.   .   .   NAME-p..autotmp_2 esc(N) Class:PAUTO Offset:0 AutoTemp OnStack Used int tc(1) # x.go:4:7
.   .   .   NAME-p.a esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:8
.   .   AS tc(1) # x.go:4:7
.   .   .   NAME-p.a esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:8
.   .   .   NAME-p.b esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:11
.   .   AS tc(1) # x.go:4:7
.   .   .   NAME-p.b esc(no) Class:PPARAM Offset:0 OnStack Used int tc(1) # x.go:3:11
.   .   .   NAME-p..autotmp_2 esc(N) Class:PAUTO Offset:0 AutoTemp OnStack Used int tc(1) # x.go:4:7

Upvotes: 2

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85633

Yes, it is. When you have same variable type, you can swipe them.

i := []int{1, 2, 3, 4}
i[0], i[1], i[2], i[3] = i[3], i[2], i[1], i[0]
// now, i is: []int{4, 3, 2, 1}
// btw, you could also range over slice and swipe them

From the docs

In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:

  1. Any typed value may be assigned to the blank identifier.
  2. If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first implicitly converted to its default type.
  3. If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first implicitly converted to type bool.

Upvotes: 0

Related Questions