大概八年前,写过这样一篇文章:不使用中间变量来交换变量的值,后来面试的时候常常遇到这题,最近翻出来看,发现当时对这个问题的理解不够深刻,所以今天又整理了一下。
1. 一些有限制的方法
字符串版本
1 2 3 4 5 6
| <?php $a = "a"; $b = "b"; $a .= $b; $b = str_replace($b, "", $a); $a = str_replace($b, "", $a);
|
1 2 3 4 5 6
| <?php $a = "a"; $b = "b"; $a .= $b; $b = substr($a, 0, (strlen($a) - strlen($b))); $a = substr($a, strlen($b));
|
上面这两个方法使用了字符串替换和截取的方法,有一个限制就是只适用于字符串。
加减法
1 2 3 4 5
| a = 1 b = 2 a = a + b b = a - b a = a - b
|
1 2 3 4 5
| a = 1 b = 2 a = b - a b = b - a a = b + a
|
乘除法
1 2 3
| a = a * b b = a / b a = a / b
|
用除法来解决这个问题,多了一个限制,b不能等于0
一句话版本
这些方法利用了表达式的返回值
所有的加减乘除的方法里有两方面限制:
看到网上有一些人提出适用+和*的时候会导致结果向上溢出,但其实这并不影响结果,因为最后逆操作会产生一次向下溢出。
eval版
eval版本可能有两个问题
异或版本
1 2 3 4 5 6
| <?php $a=10; $b=12; $a=$a^$b; $b=$a^$b; $a=$a^$b;
|
下面是简化版本
1 2 3 4
| <?php $a ^= $b; $b ^= $a; $a ^= $b;
|
异或适用于整数和字符串
2. 适用于所有的数据类型,并且没有限制的方法
对象版
1 2 3
| a = {a : b, b : a} b = a.b a = a.a
|
数组版
1 2 3
| a = [a,b] b = a[0] a = a[1]
|
匿名函数版
1 2 3 4 5 6 7 8
| a=(function(){ try { return b } finally { b = a } })()
|
PHP 版本
1
| list($var1, $var2) = [$var2, $var1];
|
Python&Ruby版本
ES6 版本
3. 总结一下
解决这个问题的基本思想有以下几种:
将两个变量同时放入其中一个变量,再分别取出,例如字符串版本,数组版本,对象版本
将两个变量通过某种计算的结果放入其中一个变量,再用计算结果和另一个已知变量逆向取回结果,例如异或版本和一部分加减乘除的版本
利用语言特性,例如eval版本,匿名函数版本,php版本和python&ruby版本