在日常编程中,我们经常涉及到交换两个变量的值,常见实现如下。
func inplaceSwap(a, b int) (int, int) {
c := a
a = b
b = c
return a, b
}
func main() {
println(inplaceSwap(1,2))
}
// output 2 1
当然,你也可以使用
a, b = b, a
来快速交换两个变量的值。
利用中间变量,快速简单又快速的实现了变量的交换。但今天发现一种高逼格的实现,虽然并没什么用,如下:
func inplaceSwap(*a, *b int) (*int, *int) {
*b = *a ^ *b
*a = *a ^ *b
*b = *a ^ *b
return a, b
}
func main() {
a := 1
b := 2
inplaceSwap2(&a, &b)
fmt.Printf("a=%v, b=%v\n", a, b) // a=2, b=1
}
在此过程中,没有用到任何临时变量,而是由下面这特性完成的。
对于任意向量 a,有 a ^ a = 0
我们假设变量 a 的内存地址为 0x80,变量 b 的内存地址为 0x90,则换算成二进制为:
a := 0x80
b := 0x90
// a = 1000 0000
// b = 1001 0000
// a ^ b = 0001 0000
则对于上面的三行运算
// 第一行
*b = *a ^ *b // 1000 0000 ^ 1001 0000 => *b = 0001 0000
// 第二行,这行计算完成后,变量 a 的内存地址已成功换为变量 b 的地址
*a = *a ^ *b // 1000 0000 ^ 0001 0000 => *a = 1001 0000
// 第三行,这行计算完成后,变量 b 的内存地址已成功换为变量 a 的地址
*b = *a ^ *b // 1001 0000 ^ 0001 0000 => *b = 1000 0000
至此,通过上三行代码,我们成功的将两个变量的内存地址交换,且没有用到零时变量。
这种交换的方式并没有性能上的优势,它仅仅是一个智力游戏。 — 深入理解计算机系统
但是这种有一个严重的弊端,当变量 a 和 b 是同一个变量时,将会导致其值为 0。
a := 0x80
b := 0x80
// a ^ b = 10000000 ^ 10000000 = 00000000
// 这将导致变量 b 的指针地址指向的值为 0
// *b = *a ^ *b => *b = 0
// 而 a 和 b 指向的同一个地址,故 &a = 0,
// 后面即使再多操作,也只是在操作 0,本质不会发生变化。