6.1 位运算符与溢出运算符
很多编程语言都支持位运算符,位运算符的主要功能是对二进制数据进行位运算等操作。而溢出运算符是Swift语言独有的,由于Swift语言对代码安全性的注重,正常的运算是不允许出现溢出行为的,开发者使用溢出运算符可以控制是否允许溢出运算。
6.1.1 位运算符的应用
在计算机中,数据都是以二进制的形式存储的,位运算是专门针对二进制数据的一种运算方式。在Swift语言中,开发者在创建数值变量时可以通过追加“0b”前缀的方式将数值设置为二进制。使用Xcode开发工具创建一个名为AdvancedOperators的Playground文件,在其中进行代码演示。创建一个UInt8类型的变量,将十进制数8以二进制的方式赋值,示例如下:
//十进制数8 var a:UInt8 = 0b1000
前面介绍过UInt8类型,其为8位的无符号整型,也就是说,任何一个UInt8类型的变量都是采用8个二进制位来存储数据的。因此,读者可以理解为a变量实际存储的数据为00001000。位运算的实质是对数据的每一个二进制位进行逻辑运算。
Swift语言支持C/Objective-C语言中的全部位运算符,其中包括按位取反运算、按位与运算、按位或运算、按位异或运算、按位左移运算以及按位右移运算。
按位取反运算符“~”的作用是将数据的每一位都进行取反操作,即如果当前位为0,则运算后变为1,如果当前位为1,则运算后变为0。对上面创建的变量a进行按位取反运算后,其存储的数据将变为11110111,即十进制数247,示例如下:
//运算后 a 的值变为十进制数247 a = ~a
按位与运算符“&”需要有两个操作数,其作用是将两个操作数相同的位进行逻辑与运算。即如果两个对应位的值都为1,则运算后此位结果为1;如果其中有一个位的值为0,则运算后此位结果为0。示例如下:
//使用二进制数11110000与a进行按位与运算,运算结果为11110000,即十进制数240 a = 0b11110000&a
按位或运算符“|”需要有两个操作数,其作用是将两个操作数相同的位进行逻辑或运算。即如果两个对应位的值有一个为1,则运算后此位结果为1;如果两个对应位的值都为0,则运算后此位结果为0。示例如下:
//使用二进制数11111111与a进行按位或运算,结果为11111111,即十进制数255 a = 0b11111111|a
按位异或运算符“^”需要有两个操作数,其作用是将两个操作数相同的位进行逻辑异或运算。即如果两个对应位的值相同,则运算后此位的值为0;如果两个对应位的值不同,则运算后结果为1。示例如下:
//使用二进制数11110000与a进行按位异或运算,结果为00001111,即十进制数15 a = 0b11110000^a
按位左移运算符“<<”用于将数据每一位上的值进行左移操作,示例如下:
//将a按位左移1位,结果为00011110,即十进制数30 a = a<<1
与按位左移运算对应,按位右移运算符“>>”用于将数据每一位上的值进行右移操作,示例如下:
//将a按位右移1位,结果为00001111,即十进制数15 a = a>>1
提示
进行按位左移或者右移运算的时候,有可能出现丢失数据位的情况,例如对于UInt8类型,将二进制数据00001111向左移动6位,结果为11000000;将二进制数据11110000向右移动6位,结果为00000011。
6.1.2 溢出运算符
Swift语言十分注重安全性,在编写代码时,如果出现了数据溢出,会直接出现运行时错误。而溢出运算符这种设计将代码的不确定性降低了很多。所谓溢出,是指超出数据所属类型的最大值或者最小值。以UInt8来说,其最大值为二进制数11111111,即十进制数255。如果将UInt8类型的变量设置为255后再将其加1,就会出现数据溢出,示例如下:
var b:UInt8 = 255 //代码运行到这里会出现错误,运行直接中断 b = b+1
如果开发者确实需要溢出操作,而不是无意留下的小错误,Swift语言中也提供了支持溢出操作的溢出操作符,示例如下:
var b:UInt8 = 255 //进行支持溢出的加操作,b的值将变为0 b = b &+ 1 //进行支持溢出的减操作,b的值将变为255 b = b &- 1 //进行支持溢出的乘操作,b的值将变为254 b = b &* 2
提示
对二进制数据进行乘2运算,实质上就是对二进制数据进行左移一位的运算,例如二进制数据11111111*2=11111110。