Swift------高级操作符

1、概述

除了一些基本的操作符,Swift提供了几种能够执行更加复杂值操纵的高级操作符。其中包括你所熟悉的C和OC中的按位位移操作符。

与C语言的算数运算符不同,Swift中的算数操作符默认不会溢出(overflow)。溢出行为被捕获并且作为一个错误被报告。如果要参与溢出行为,使用Swift的默认会溢出的第二套算数操作符,例如溢出加(&+)。Swift中的会溢出的操作符都以&开头。

Swift允许为你自定义的类型提供自己的标准操作符实现。

Swift允许自由的定义你自己的自定义的中缀,前缀,后缀,赋值操作符,以及自定义的优先级和结合律。并且你可以扩展已存在的类型来支持你定义的自定义操作符。

2、位操作符

位操作符允许操纵数据结构中的独立的原始数据位。常用于低级别的程序,例如图形程序和设备驱动创建。当你工作于来自外部源的原始数据,例如通过自定义协议交流的数据的编解码,位操作符也是很有用的。

1)位NOT操作符(~),翻转一个数字中的所有位。前缀操作符,直接在值的前面,没有空格

NOT操作符

例:let initialBits: UInt8 = 0b00001111
       let invertedBits = ~initialBits     //等于11110000

2)位AND操作符。从两个被操作数返回一个新的值,只有两个被操作数对应位都为1,返回值的对应位才为1.

AND操作符

例: let firstSixBits: UInt8 = 0b11111100
        let lastSixBits: UInt8 = 0b00111111
        let middleFourBits = firstSixBits & lastSixBits //等于0b00111100

3)位OR操作符。从两个被操作数返回一个新的值,只要两个被操作数对应位任意一个为1,返回值的对应位就为1.

OR操作符

例:let someBits: UInt8 = 0b10110010
       let moreBits: UInt8 = 0b01011110
       let combinedbits = someBits | moreBits //等于0b11111110

4)位XOR操作符。异或操作符(^)。操作符返回一个新的值,返回值的每一位是:被操作的两个数对应位不相同返回1,相同返回0

XOR操作符

例:let firstBits: UInt8 = 0b00010100
       let otherBits: UInt8 = 0b00000101
       let outputBits = firstBits ^ otherBits //等于0b00010001

5)按位左移和右移操作符。逻辑位移(logic shift)。按位左移(<<)有乘以2的效果,按位右移(>>)有除以2的效果。

无符号整数的移位行为:
(1)存在的位被左移或者右移相应的位数
(2)移动之后超出整数存储范围的位抛弃
(3)原始位左移右移之后空出的位置0

左移右移实例

例:let shiftBits: UInt8 = 4  // 00000100 in binary
       shiftBits << 1  // 00001000
       shiftBits << 2  // 00010000
       shiftBits << 5  // 10000000
       shiftBits << 6  // 00000000
       shiftBits >> 2  // 00000001
有符号整数的位移行为:有符号整数使用第一位标明整数是正(0)的还是负(1)的。剩余的为存储实际的值。
正整数存储于无符号整数相同,除了最高位为0,代表是正值:

有符号正整数4

负整数存储有一些不同。它们存储的是2的n次方减去它的绝对值,其中n代表值的位数。一个8位数有7位值位:

有符号负整数-4

这种负数编码方式叫做二进制补码(two's complement)。这种表示方法有几个好处:
(1)加法运算。如-1+-4。只需要执行标准的8位二进制加法即可,抛弃任何超出的部分

-1 + -4

(2)负数的位移操作和正数位移得以统一。有一个规则:当你右移有符号整数,规则与无符号整数一样,只是填充空余位为标志位而不是0。这样保证了右移之后符号位相同,被称为算术位移(arithmetic shift)

有符号整数右移

2、溢出操作符

如果你试图给一个不能保留这个值的整形常量或变量插入一个值,默认情况下,Swift报一个错误,而不是允许一个无效的值被创建。这个行为保证了安全性。超出范围的赋值会引起错误:
var potentialOverflow = Int16.max
// potentialOverflow等于32767, Int16的最大值
potentialOverflow+=1
// Error
当你特别的需要溢出条件来阶段可用位的数字,Swift提供三种算术溢出操作符,允许整数计算的溢出行为。这些操作符都以&开头:

Overflow addtion (&+)
Overflow subtraction (&-)
Overflow multiplication (&*)

1)值溢出。数字可以在正数和负数两个方向都溢出。例:
var unsignedOverflow = UInt8.max
// unsignedOverflow 等于255, UInt8的最大值
unsignedOverflow=unsignedOverflow&+1
// unsignedOverflow现在等于0

无符号溢出加法

var unsignedOverflow = UInt8.min
// unsignedOverflow等于0, UInt8最小值
unsignedOverflow = unsignedOverflow&-1
// unsignedOverflow等于255

无符号溢出减法

有符号整数的溢出计算,符号位也作为加减数字的一部分来计算。例:
var signedOverflow=Int8.min
// signedOverflow等于-128, Int8的最小值
signedOverflow=signedOverflow&-1
// signedOverflow等于127

有符号整数减法

对于有符号和无符号整数,正方向的溢出计算回环从最大有效值到最小有效值。负方向的溢出计算回环从最小有效值到最大有效值。

3、优先级和结合律

操作符优先级使得一些操作符比其他操作符有更高的优先级,优先级高的先实施。操作符结合律定义了同一优先级的操作符怎么来组合。操作符优先级解释了以下表达式等于17:
2 + 3 % 4 * 5
高优先级的操作符比低优先级的先计算。而同一级别优先级操作符哪个先计算由结合律来确定,等同于隐式的添加了括号:
2 + ((3 % 4)* 5)

4、操作符方法(operator methods)

类和结构体可以提供已存在操作符的自己的实现,这成为操作符重载(overloading the existing operators)。下面的例子实现了结构体内算法加操作符,二元中缀操作符(binary infix operator):
struct Vector2D{
  var x=0.0,y=0.0
}
extension Vector2D{
    static func + (left:Vector2D,right:Vector2D) ->Vector2D{
        returnVector2D(x:left.x+right.x,y:left.y+right.y)
    }
}

let vector = Vector2D(x:3.0,y:1.0)
let anotherVector = Vector2D(x:2.0,y:4.0)
let combinedVector = vector+anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)

前缀和后缀操作符。通过在func关键字前面写prefix和postfix来实现前缀或者后缀一元操作符:
extension Vector2D{
    static prefix func - (vector:Vector2D) ->Vector2D{
        returnVector2D(x: -vector.x,y: -vector.y)
    }
}
let positive=Vector2D(x:3.0,y:4.0)
let negative= -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive= -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0)

混合的赋值操作符(compound assignment operators)。其方法重载需标记左输入参数类型为inout。例:
extension Vector2D{
    static func += (left:inoutVector2D,right:Vector2D) {
        left=left+right
    }
}
var original = Vector2D(x:1.0,y:2.0)
let vectorToAdd = Vector2D(x:3.0,y:4.0)
original += vectorToAdd
// original now has values of (4.0, 6.0)
赋值操作符和三元条件操作符不能被重载(overload)
相等操作符(equivalence operators)。为自定义类型实现相等操作符实现与其他中缀操作符一样。例:
extension Vector2D{
    static func ==  (left:Vector2D,right:Vector2D) ->Bool{
        return(left.x==right.x) && (left.y==right.y)
    }
    static func !=  (left:Vector2D,right:Vector2D) ->Bool{
        return!(left==right)
    }
}
let twoThree = Vector2D(x:2.0,y:3.0)
let anotherTwoThree = Vector2D(x:2.0,y:3.0)
if twoThree == anotherTwoThree{
    print("These two vectors are equivalent.")
}
// Prints "These two vectors are equivalent."

5、自定义操作符

新的操作符声明在一个全局级别,使用operator关键字,并且以prefix、infix、postfix做修饰符。例:
extension Vector2D{
    static prefix func +++ (vector:inoutVector2D) ->Vector2D{
        vector+=vector
        return vector
    }
}
var toBeDoubled = Vector2D(x:1.0,y:4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)
注意与运算符重载的区别

自定义中缀运算符的优先级。一个自定义的中缀运算符如果没有显示的放进一个优先级组,那么它会被富裕一个默认的优先级组,高于三元条件运算符的优先级。下面的例子定义了一个新的自定义中缀运算符+-。从属于运算符组AdditionPrecedence:
infix operator +- : AdditionPrecedence
extension Vector2D{
    static func +-  (left:Vector2D,right:Vector2D) ->Vector2D{
        returnVector2D(x:left.x+right.x,y:left.y-right.y)
    }
}
let firstVector = Vector2D(x:1.0,y:2.0)
let secondVector = Vector2D(x:3.0,y:4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)

AdditionPrecedence的具体细节参考Swift语言参考Operators章节
不需要对前缀或者后缀操作符指定优先级,如果对一个操作数同时应用了前缀以及后缀运算符,后缀运算符首先起作用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容