博客地址:http://www.flakor.cn/2014-06-06-531.html
第2章 基本运算符
运算符(operator)是用于检查、更改或组合值的特殊符号或短语。例如,加法运算符(+)求两个数字的加和(如let i = 1 + 2)。更复杂的例子包括逻辑与(logical AND)运算符&&(如 if enteredDoorCode && passedRetinaScan) 以及自增运算符 ++i,后者是将 i 存储的值加上 1 的便捷写法。
Swift 支持标准 C 的大多数运算符,并改进了部分行为特性,以避免常见的编码错误。赋值运算符(=)不会返回值,这样可避免在打算使用等于运算符(==)的地方误用前者。算术运算符(+、-、*、/、% 等)会侦测并阻止值溢出,可避免处理超出可存储值域范围的数时出现意料之外的结果。如果需要支持溢出,可以选用Swift 的溢出运算符,详见 溢出运算符。
与 C 语言不同,Swift 允许对浮点数求余(%)。Swift 还提供了两种 C 语言没有的范围运算符(a..b 与 a...b),作为表达值域范围的便捷写法。
本章讲解 Swift 中的常用运算符。高级运算符一章涉及了 Swift 的高级运算符,并讲解了如何自定义运算符,以及让标准运算符支持自定义类型的运算。
术语
运算符有一元,二元,三元:
一元运算符只能作用与目标(如 -a). 一元前缀运算符紧跟在目标数之前(such as !b),一元后缀运算符则紧跟在目标数之后(such as i++).
二元运算符作用与两个目标(如 2 + 3)。因为它出现在两个目标数之前,所以是中缀。
三元运算符作用与三个目标.。和C一样,Swift 只有一个三元运算符(a ? b : c)。
运算符作用的变量称为操作数(operand),在表达式:1 + 2 中, 加号(+)是二元运算符,他的两个操作数是值1和2。
赋值运算符
赋值运算符 (a = b) 初始化或更新一个带值的b的值:
[code] let b = 10 var a = 5 a = b // a现在等于10 [/code]
如果赋值等号右边是一个带多个值的元组,元组的元素能够一次性并被分解赋值给多个常量或变量:
[code] let (x, y) = (1, 2) // x等于1,y等于2[/code]
与C和Objective-C中的不同, Swift中的赋值本身不返回值。以下的表达式是错误的:
[code]if x = y { // 这是错误的, 因为x = y不返回值 }[/code]
这个特性防止在想要使用等于运算符(==)时却意外的用了赋值运算符(=)。通过使if x = y非法, Swift帮助你在代码中避免出现类似错误。
算术运算符
Swift 为所有的数字类型提供4种基本算术运算符支持:
加法(+)
减法 (-)
乘法(*)
除法(/)
[code]1 + 2 // equals 3 5 - 3 // equals 2 2 * 3 // equals 6 10.0 / 2.5 // equals 4.0[/code]
与C和Objective-C的不同, Swift的算术运算符默认不允许值溢出。 你可以选择使用Swift的溢出运算符使值能溢出(如 a &+ b), 详见溢出运算符(Overflow Operators)。
加号运算符同时支持字符串拼接(String concatenation):
[code]"hello, " + "world" // 等于"hello, world"[/code]
两个字符,或一个字符和一个字符串,可以加在一起组成一个新字符串:
详见Concatenating Strings and Characters.
求余运算符
求余运算符(a % b)计算出a中能包含多少倍的b,然后返回剩余的值(称为余数).
注意:
求余运算符在其他语言里面又称为模运算符。 然而,在Swift中对于负数,这种运算行为严格地说求余运算符而不是模运算。
下面说明求余运算是怎么计算的。计算9 % 4,你先算出在9中能包含多少个4。:
你可以在9中放2个4,余下就是1 (桔色显示).
在Swift中,可以写成这样:
[code]9 % 4 // 等于 1[/code]
要确定a % b的结果, %运算符计算下列的方程式,然后返回余数作为输出:
a = (b × 倍数) + 余数
其中倍数是a中能存放b的最大倍数。
将 9 和4分别作为a,b带入这个方程式:
9 = (4 × 2) + 1
计算负数也使用同样的方式:
[code]-9 % 4 // equals -1[/code]
将-9和4带入方程式:
-9 = (4 × -2) + -1
得到余数-1.
如果b是负数,负数符号被忽略。也就是说a % b 和 a % -b 总是得到一样的答案。
浮点求余运算
和C,Objective-C中的求余运算不同, Swift中的浮点也能执行求余运算:
8 % 2.5 // equals 0.5
在此例中, 8初一2.5等于3, 余是0.5, 所以求余运算返回双浮点值0.5。
自增自减运算符
像C一样, Swift提供自增(++)和自减(--)运算符,以便快捷地对数字进行增加或减少1。你可以对任意的整形(integer)和浮点型(floating-point)使用这两个运算符。
var i = 0
++i // i now equals 1
你每次执行++i, i的值便加1。基本上可以说++i就是i = i + 1的简写,同理,--i可作为i = i - 1的简写使用。
++ 和 -- 符号可以作为前缀或后缀运算符使用。 ++i和i++ 是对i的值增加1的两种可行方式。相似地,,--i和 i--便是两种对i的值减1的可行方法 。
值的注意的是这几个运算符都不但改变i的值而且返回它的值。如果你只是想增加或减少i的值,你可以无视返回值。但是,如果你确实需要使用返回值,那么返回值基于以下规则,根据你使用的运算符是前缀还是后缀而返回不同的值:
如果运算符写在变量前,它会在返回变量的值之前先进行加一或减一运算。
如果运算符写在变量后,它会在返回变量的值之后才进行加一或减一运算。
例如:
[code]var a = 0 let b = ++a // a,b现在都等于 1 let c = a++ // a现在等于2,但是c被设为自加之前的值,即1。[/code]
在上例中, let b = ++a 在返回前先自加,所以a和b都等于计算后的新值1.
然而, let c = a++ 在返回后自加,也就是说c得到的是旧值1, 而a更新至2.
除非你将i++用于特殊情况, it is recommended that you use ++i and --i in all cases, because they have the typical expected behavior of modifying i and returning the result.
一元减号运算符
数字的正负号可用前缀一元减号元素-号切换。:
[code]let three = 3 let minusThree = -three // minusThree equals -3 let plusThree = -minusThree // plusThree equals 3, or "minus minus three"[] 一元减号运算符(-)要直接紧跟在它要计算的值之前,中间不能有空格。 一元加号运算符 一元加号运算符(+)只是简单地返回操作的值,并无任何变化: [code]let minusSix = -6 let alsoMinusSix = +minusSix // alsoMinusSix equals -6[/code]
尽管一元加号运算符不做任何事,你也可以在同时使用一元减号运算符作负数的情况下,使用它作正数来美化你的代码。
复合赋值运算符
和C一样,Swift提供复合赋值运算符,将其他运算和赋值运算组合在一起。一个简单的例子便是加法赋值运算符(+=):
[code]var a = 1 a += 2 // a is now equal to 3[/code]
表达式a += 2是a = a + 2的简写。实际上,加法和赋值被组合在一个运算符中,并同时实行加法和赋值。
注意:
复合赋值运算符无返回值。你不能写成let b = a += 2。这和上面提及的自增自减运算符不同。
完整复合赋值运算符的列表可在Expressions中找到。
比较运算符
Swift 支持所以标准C的比较运算符:
等于(a == b)
不等于 (a != b)
大于 (a > b)
小于 (a < b) 大于或等于 (a >= b)
小于或等于 (a <= b) 注意 Swift还提供两种特性运算符(=== and !==)。你可以使用这两种运算符来测试两个对象是否为同一个对象的实例。更多内容,详见Classes and Structures. 每个比较运算符都返回一个代表表达值真假的布尔值类型(Bool):
[code]1 == 1 // true, because 1 is equal to 1 2 != 1 // true, because 2 is not equal to 1 2 > 1 // true, because 2 is greater than 1 1 < 2 // true, because 1 is less than 2 1 >= 1 // true, because 1 is greater than or equal to 1 2 <= 1 // false, because 2 is not less than or equal to 1[/code]
比较运算符经常用于条件表达式,如if语句:
[code]let name = "world" if name == "world" { println("hello, world") } else { println("I'm sorry \(name), but I don't recognize you") } // prints "hello, world", because name is indeed equal to "world"[/code]
更多关于if语句,见Control Flow.
三元条件运算符
三元条件运算符是以 问题 ? 答案1 : 答案2 三个部分的形式出现的特殊运算符。它是根据问题的真假来决定到底计算两个表达式的哪一个的。如果问题是真,它计算答案1然后返回它的值;否则,它计算答案2然后返回答案2的值。
三元条件运算符是下列代码的简写:
[code]if question { answer1 } else { answer2 }[/code]
这里有一个计算列表行的像素高(the pixel height)的例子。如果这一行有头(header),行高就应该比内容的高度大50像数,否则就比内容高20像数:
[code]let contentHeight = 40 let hasHeader = true let rowHeight = contentHeight + (hasHeader ? 50 : 20) // rowHeight is equal to 90[/code]
以上例子是下列代码的简写:
[code]let contentHeight = 40 let hasHeader = true var rowHeight = contentHeight if hasHeader { rowHeight = rowHeight + 50 } else { rowHeight = rowHeight + 20 } // rowHeight is equal to 90[/code]
使用的三元条件运算符的第一个例子能在一行代码内将rowHeight设置为正确的值。这比第二个例子简明, 也使rowHeight不需要是变量,因为它的值在if语句中无需改变。
三元条件运算符提供了一种简明扼要的方法来决定两个表达式中哪个被执行。当然也要慎重使用三元条件运算符。它的简明如果被滥用也会导致代码难以阅读。要避免将多个三元条件运算符组合成一个符合表达式的做法。
区间运算符
Swift包括两种用于表达值范围的区间运算符
闭区间运算符
闭区间运算符 (a...b) 定义一个从a到b的范围,并包括a和b。
当你要遍历一个范围内每个值的时候,闭区间运算符十分有用,如在for-in循环中:
[code]for index in 1...5 { println("\(index) times 5 is \(index * 5)") } // 1 times 5 is 5 // 2 times 5 is 10 // 3 times 5 is 15 // 4 times 5 is 20 // 5 times 5 is 25[/code]
更多for-in循环见Control Flow.
半闭区间运算符
半闭区间运算符(a..b)定义一个从a到b的范围,但是不包含b。说它半闭,是因为它包含第一个值,而不包含最后一个。
当你操作从0开始的列表如数组时,半闭区间运算符特别有用。它用于计数至列表长度(但不包括长度):
[code]let names = ["Anna", "Alex", "Brian", "Jack"] let count = names.count for i in 0..count { println("Person \(i + 1) is called \(names[i])") } // Person 1 is called Anna // Person 2 is called Alex // Person 3 is called Brian // Person 4 is called Jack[/code]
注意,数组包含4个物品,但是0..count 只计数到3(数组中最后一个元素的索引)。因为这是半闭区间。更过关于数组的,详见Arrays。
逻辑运算符
逻辑运算符改变或组合两种布尔逻辑值——真和假。Swift提供三种类似C语言的基本的逻辑运算符:
逻辑非 (!a)
逻辑与 (a && b)
逻辑或 (a || b)
逻辑非运算符
逻辑非运算符 (!a) 反转一个布尔值,所以真变假,假变真。
逻辑非运算符使前缀运算符,跟着在操作数之前,中间无空格。它可以读作“不是a”,见下例:
[code]let allowedEntry = false if !allowedEntry { println("ACCESS DENIED") } // prints "ACCESS DENIED"[/code]
if !allowedEntry 短语可读作“如果不允许进入”,下一行只有在“not allowed entry”是真的时候在执行; 也就是说, if allowedEntry是fasle.
正如此例,合理选择布尔常量或变量的名字可使代码具备可读性同时简洁扼要,同时要避免两次取反或混乱的逻辑语句。
逻辑与运算符
逻辑与运算符(a && b)创建了一个如果两个值都为真则整个表达式为真的逻辑表达式。
如果任一个值为假, 整个表达式为假。实际上,如果第一个值为假,第二个值根本不会被计算,因为它不可能是整个表达式为真。这被叫做短路求值。
例子计算两个布尔值。只有当两个值都为真才允许进入:
[code]let enteredDoorCode = true let passedRetinaScan = false if enteredDoorCode && passedRetinaScan { println("Welcome!") } else { println("ACCESS DENIED") } // prints "ACCESS DENIED"[/code]
逻辑或运算符
逻辑或运算符(a || b)是一个由两个管道字符(|是shell管道符号)组成的中缀运算符。你可以用它来创建一个逻辑表达式。这个表达式只要任意其中一个值为真,整个表达式便为真。
像上面的逻辑与运算符,逻辑或运算符也使用短路求值来计算表达式。如果左边的值为真,那么右边就不用计算,因为它改变不了整个表达式的输出值。
在下面的例子中,,第一个布尔值(hasDoorKey)是假(false),但是第二个值(knowsOverridePassword)是真(true)。 因为有一个值为真,所以整个表达式也为真,允许进入(access is allowed):
[code]let hasDoorKey = false let knowsOverridePassword = true if hasDoorKey || knowsOverridePassword { println("Welcome!") } else { println("ACCESS DENIED") } // prints "Welcome!"[/code]
复合逻辑运算符
你可以组合多个逻辑运算符来创建一个长复杂的符合表达式:
[code]if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword { println("Welcome!") } else { println("ACCESS DENIED") } // prints "Welcome!"[/code]
例子使用的多个&&和||运算符来创建了一个再复合表达式。尽管如此,&& 和|| 运算符依旧操作两个值,所以这实际上是三个小的表达式串联在一起。它可读作:
如果我们已经进入了输入了正确的门牌号,并通过了视网膜扫描,或者如果我们有可用的门钥匙,又或者我们知道紧急替代密码(the emergency override password),那么便可以进入
根据enteredDoorCode, passedRetinaScan,hasDoorKey的值,前两个短表达值是假的。但是,紧急替代密码是知道的,所以整个表达式还是被计算为真。
明确的括号
有时候式子并不严格需要括号,但是为了使整个表达式的含义更易读懂,加入括号是很有益的。
在上面的进门例子中,在符合表达式的第一部分加入括号,能使它的含义更明确:
[code]if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword { println("Welcome!") } else { println("ACCESS DENIED") } // prints "Welcome!"[/code]
括号使前两个值在整体逻辑中清楚地视为一个单独的可能状态的一部分。复合表达式的值并没有改变,但是整个表达式含义对于阅读者来说更加清晰。可读性总是比简短更,;在可以帮助你的含义变清晰的地方使用括号 。