换一种方式,交换两个变量的值

换一种方式,交换两个变量的值

  1. PHP
  2. 3 years ago
  3. 3 min read

在日常编程中,我们经常涉及到交换两个变量的值,常见实现如下。

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,本质不会发生变化。

php