swap

Posted on By ᵇᵒ

交换两个变量的值

交换两个变量的值是很常见的操作,通常的做法都是借个临时变量来完成交换:

fun foo() {
    var a = 0
    var b = 1

    val temp = a
    a = b
    b = temp
}

这种写法一方面繁琐,另一方面还需要增加额外的临时变量。稍微逼格化一下:

fun foo() {
    var a = 0
    var b = 1

    a = b.apply { b = a }
}

但是,作为一个有志青年,在优化道路上永无止尽的我们显然还是不满足。联想到 kotlin 有个中缀操作符,要是我们自定义一个 swap 操作符那该多好啊,这样一来代码就简化多了:

fun foo() {
    var a = 0
    var b = 1

    a swap b
}

至此,仿佛已经看见了胜利的曙光。但理想是美好的,现实却是残酷的。事实是 kotlin 没有任何办法实现 swap 中缀操作符!

/styles/images/swap/what.jpeg

是的,你没有看错,kotlin 无法实现 swap 中缀操作符。不信?来我们尝试一下,假如有 swap 中缀操作符,那么大概应该是这个样子的:

public infix fun Number.swap(other: Number): Unit {
    this = other.apply { other = this }
}

然而,这段代码直接编译告警,根本无法运行。中缀操作的两端都是 val 值,无法在 swap 函数里对其重新赋值。
有的朋友会纳闷儿,我们明明是需要对变量进行交换,怎么成了对 Number 类进行中缀操作呢?这是因为 kotlin 没有变量类型的类,如果有,它大概会叫做指针。

还记得这个经典的 java 陷阱吗:

public static final void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

由于 java 函数是值传递,而非引用传递,上面这段代码属于自欺欺人。这一切皆是源自 java 没有指针。

所以,最后,正确的交换方式是?

/styles/images/swap/taijian.jpeg