提问人:xmllmx 提问时间:6/4/2023 更新时间:6/6/2023 访问量:119
在 golang 中用 'a, b = b, a' 交换两个整数是否安全?
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)
}
输出为:
Before Swap: 1 2
After Swap: 2 1
看起来不错。我只是想知道:
在 golang 中交换两个整数是否安全?a, b = b, a
答:
0赞
Bhojendra Rauniyar
6/4/2023
#1
是的,它是。当您具有相同的变量类型时,您可以滑动它们。
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
从文档
在赋值中,每个值必须可赋值给分配给它的操作数类型,但存在以下特殊情况:
- 任何类型化值都可以分配给空白标识符。
- 如果将非类型化常量分配给接口类型的变量或空白标识符,则该常量将首先隐式转换为其默认类型。
- 如果将非类型化的布尔值分配给接口类型的变量或空白标识符,则首先将其隐式转换为类型 bool。
评论
0赞
cuonglm
6/6/2023
我不确定你的引述是否解释了为什么在赋值中交换两个变量是安全的。正确的引文应该是描述评估和分配顺序的段落。
2赞
cuonglm
6/6/2023
#2
是的,使用以下命令交换两个变量是安全的:
a, b = b, a
分配分两个步骤进行:
- 首先评估作业的右侧。
- 然后,评估值将按从左到右的顺序分配给左侧。
换句话说,将大致重写为:a, b = b, a
tmpB := b
tmpA := a
a = tmpB
b = tmpA
这就是为什么作业是安全的。
事实上,编译器足够聪明,可以避免第二个临时变量,因此将被重写为:a, b = b, a
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
下一个:悬空引用和未定义的行为
评论