• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Swift高级运算符

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

除了基本操作符中所讲的运算符,Swift还有很多复杂的高级运算符,包含了C语和Objective-C中的位运算符和移位运算。

 

不同于C语言中的数值计算。Swift的数值计算默认是不可溢出的。溢出行为会被捕获并报告为错误。

你是有益的?好吧,你能够使用Swift为你准备的还有一套默认同意溢出的数值运算符,如可溢出加&+。

全部同意溢出的运算符都是以&開始的。

 

自己定义的结构,类和枚举。能否够使用标准的运算符来定义操作?当然能够。在Swift中。你能够为你创建的全部类型定制运算符的操作。

 

可定制的运算符并不限于那些预设的运算符,自己定义有个性的中置。前置,后置及赋值运算符。当然还有优先级和结合性。

这些运算符的实现能够运用预设的运算符,也能够运用之前定制的运算符。

 

位运算符

位操作符通常在诸如图像处理和创建设备驱动等底层开发中使用,使用它能够单独操作数据结构中原始数据的比特位。在使用一个自己定义的协议进行通信的时候,运用位运算符来对原始数据进行编码和解码也是很有效的。

 

Swift支持例如以下全部C语言的位运算符:

 

按位取反运算符

按位取反运算符~对一个操作数的每一位都取反。

这个运算符是前置的,所以请不加不论什么空格地写着操作数之前。

  1. let initialBits: UInt8 = 0b00001111 
  2. let invertedBits = ~initialBits  // 等于 0b11110000 

UInt8是8位无符整型,能够存储0~255之间的随意数。这个样例初始化一个整型为二进制值00001111(前4位为0,后4位为1)。它的十进制值为15。

 

使用按位取反运算~对initialBits操作,然后赋值给invertedBits这个新常量。这个新常量的值等于全部位都取反的initialBits,即1变成0。0变成1。变成了11110000,十进制值为240。

 

按位与运算符

按位与运算符对两个数进行操作,然后返回一个新的数。这个数的每一个位都须要两个输入数的同一位都为1时才为1。

下面代码。firstSixBits和lastSixBits中间4个位都为1。

对它俩进行按位与运算后,就得到了00111100。即十进制的60。

  1. let firstSixBits: UInt8 = 0b11111100 
  2. let lastSixBits: UInt8  = 0b00111111 
  3. let middleFourBits = firstSixBits & lastSixBits  // 等于 00111100 

按位或运算

按位或运算符|比較两个数。然后返回一个新的数,这个数的每一位设置1的条件是两个输入数的同一位都不为0(即随意一个为1,或都为1)。

例如以下代码,someBits和moreBits在不同位上有1。按位或执行的结果是11111110。即十进制的254。

  1. let someBits: UInt8 = 0b10110010 
  2. let moreBits: UInt8 = 0b01011110 
  3. let combinedbits = someBits | moreBits  // 等于 11111110 

按位异或运算符

按位异或运算符^比較两个数。然后返回一个数,这个数的每一个位设为1的条件是两个输入数的同一位不同,假设同样就设为0。

下面代码,firstBits和otherBits都有一个1跟还有一个数不同的。所以按位异或的结果是把它这些位置为1,其它都置为0。

  1. let firstBits: UInt8 = 0b00010100 
  2. let otherBits: UInt8 = 0b00000101 
  3. let outputBits = firstBits ^ otherBits  // 等于 00010001 

按位左移/右移运算符

左移运算符<<和右移运算符>>会把一个数的全部比特位按下面定义的规则向左或向右移动指定位数。

 

按位左移和按位右移的效果相当把一个整数乘于或除于一个因子为2的整数。

向左移动一个整型的比特位相当于把这个数乘于2,向右移一位就是除于2。

 

无符整型的移位操作

对无符整型的移位的效果例如以下:

 

已经存在的比特位向左或向右移动指定的位数。

被移出整型存储边界的的位数直接抛弃。移动留下的空白位用零0来填充。

这样的方法称为逻辑移位。

 

下面这张把展示了 11111111 << 1(11111111向左移1位)。和 11111111 >> 1(11111111向右移1位)。蓝色的是被移位的,灰色是被抛弃的。橙色的0是被填充进来的。

  1. let shiftBits: UInt8 = 4   // 即二进制的00000100 
  2. shiftBits << 1             // 00001000 
  3. shiftBits << 2             // 00010000 
  4. shiftBits << 5             // 10000000 
  5. shiftBits << 6             // 00000000 
  6. shiftBits >> 2             // 00000001 

你能够使用移位操作进行其它数据类型的编码和解码。

  1. let pink: UInt32 = 0xCC6699 
  2. let redComponent = (pink & 0xFF0000) >> 16    // redComponent 是 0xCC, 即 204 
  3. let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent 是 0x66, 即 102 
  4. let blueComponent = pink & 0x0000FF           // blueComponent 是 0x99, 即 153 

这个样例使用了一个UInt32的命名为pink的常量来存储层叠样式表CSS中粉色的颜色值,CSS颜色#CC6699在Swift用十六进制0xCC6699来表示。

然后使用按位与(&)和按位右移就能够从这个颜色值中解析出红(CC)。绿(66),蓝(99)三个部分。

 

对0xCC6699和0xFF0000进行按位与&操作就能够得到红色部分。0xFF0000中的0了遮盖了OxCC6699的第二和第三个字节,这样6699被忽略了,仅仅留下0xCC0000。

 

然后,按向右移动16位,即 >> 16。

十六进制中每两个字符是8比特位,所以移动16位的结果是把0xCC0000变成0x0000CC。

这和0xCC是相等的,都是十进制的204。

 

相同的,绿色部分来自于0xCC6699和0x00FF00的按位操作得到0x006600。然后向右移动8們,得到0x66。即十进制的102。

 

最后,蓝色部分对0xCC6699和0x0000FF进行按位与运算,得到0x000099,无需向右移位了,所以结果就是0x99。即十进制的153。

 

有符整型的移位操作

有符整型的移位操作相对复杂得多,由于正负号也是用二进制位表示的。(这里举的样例尽管都是8位的,但它的原理是通用的。)

 

有符整型通过第1个比特位(称为符号位)来表达这个整数是正数还是负数。

0代表正数,1代表负数。

 

其余的比特位(称为数值位)存储事实上值。

有符正整数和无符正整数在计算机里的存储结果是一样的。下来我们来看+4内部的二进制结构。

符号位为0,代表正数,另外7比特位二进制表示的实际值就刚好是4。

 

负数呢,跟正数不同。负数存储的是2的n次方减去它的绝对值。n为数值位的位数。一个8比特的数有7个数值位,所以是2的7次方,即128。

 

我们来看-4存储的二进制结构。

如今符号位为1,代表负数,7个数值位要表达的二进制值是124,即128 - 4。

负数的编码方式称为二进制补码表示。这样的表示方式看起来非常奇怪。但它有几个长处。

 

首先,仅仅须要对所有8个比特位(包含符号)做标准的二进制加法就能够完毕 -1 + -4 的操作。忽略加法过程产生的超过8个比特位表达的不论什么信息。

第二。因为使用二进制补码表示。我们能够和正数一样对负数进行按位左移右移的,相同也是左移1位时乘于2。右移1位时除于2。要达到此目的,对有符整型的右移有一个特别的要求:

 

对有符整型按位右移时。使用符号位(正数为0。负数为1)填充空白位。

这就确保了在右移的过程中。有符整型的符号不会发生变化。这称为算术移位。

 

正由于正数和负数特殊的存储方式。向右移位使它接近于0。移位过程中保持符号会不变。负数在接近0的过程中一直是负数。

 

溢出运算符

默认情况下。当你往一个整型常量或变量赋于一个它不能承载的大数时,Swift不会让你这么干的。它会报错。

这样。在操作过大或过小的数的时候就非常安全了。

 

比如,Int16整型能承载的整数范围是-32768到32767,假设给它赋上超过这个范围的数。就会报错:

  1. var potentialOverflow = Int16.max 
  2. // potentialOverflow 等于 32767, 这是 Int16 能承载的最大整数 
  3. potentialOverflow += 1 
  4. // 噢, 出错了 

对过大或过小的数值进行错误处理让你的数值边界条件更灵活。

 

当然。你有意在溢出时对有效位进行截断,你可採用溢出运算。而非错误处理。Swfit为整型计算提供了5个&符号开头的溢出运算符。

 

溢出加法 &+

溢出减法 &-

溢出乘法 &*

溢出除法 &/

溢出求余 &%

 

值的上溢出

以下样例使用了溢出加法&+来解剖的无符整数的上溢出

  1. var willOverflow = UInt8.max 
  2. // willOverflow 等于UInt8的最大整数 255 
  3. willOverflow = willOverflow &+ 1 
  4. // 这时候 willOverflow 等于 0 

willOverflow用Int8所能承载的最大值255(二进制11111111)。然后用&+加1。然后UInt8就无法表达这个新值的二进制了,也就导致了这个新值上溢出了,大家能够看下图。

溢出后,新值在UInt8的承载范围内的那部分是00000000。也就是0。

 

值的下溢出

数值也有可能由于太小而越界。举个样例:

 

UInt8的最小值是0(二进制为00000000)。使用&-进行溢出减1。就会得到二进制的11111111即十进制的255。

 

Swift代码是这种:

  1. var willUnderflow = UInt8.min 
  2. // willUnderflow 等于UInt8的最小值0 
  3. willUnderflow = willUnderflow &- 1 
  4. // 此时 willUnderflow 等于 255 

有符整型也有类似的下溢出,有符整型全部的减法也都是对包含在符号位在内的二进制数进行二进制减法的,这在 "按位左移/右移运算符" 一节提到过。

最小的有符整数是-128。即二进制的10000000。用溢出减法减去去1后。变成了01111111,即UInt8所能承载的最大整数127。

来看看Swift代码:

  1. var signedUnderflow = Int8.min 
  2. // signedUnderflow 等于最小的有符整数 -128 
  3. signedUnderflow = signedUnderflow &- 1 
  4. // 现在 signedUnderflow 等于 127 

除零溢出

一个数除于0 i / 0。或者对0求余数 i % 0,就会产生一个错误。

  1. let x = 1 
  2. let y = x / 0 

使用它们相应的可溢出的版本号的运算符&/和&%进行除0操作时就会得到0值。

  1. let x = 1 
  2. let y = x &/ 0 
  3. // y 等于 0 

优先级和结合性

运算符的优先级使得一些运算符优先于其它运算符,高优先级的运算符会先被计算。

该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
swift生成二维码发布时间:2022-07-13
下一篇:
[Swift]LeetCode4. 两个排序数组的中位数 | Median of Two Sorted Arrays发布时间:2022-07-13
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap