运算符是一个特殊的符号或者短句,你可以用它来检查,改变或者组合某一些值。比如,加法运算符(+)可以让2个数字相加,像在 let i = 1 + 2 中一样,有比如逻辑与运算符(&&),可以组合2个布尔值,就像在 if true && false 中一样。
Swfit支持大多数标准c语言中的运算符,还改善了部分功能,用以排除一些常见的编码错误。赋值运算符(=)不会有返回值,防止和比较运算符(==)混用。术数运算符(+,-*,/,%等),会检测并防止值溢出。避免在正在处理的值不在对应类型可以存储的值的范围之中而出现意料之外的结果。你可以选择溢出运算符来选择值溢出是采取的行为。
Swift也提供了C语言中没有的范围运算符,比如a..<b和a...b,这是表示值的范围的简写。
这一章只描述Swift中常用的运算符。在高级运算符章节中,会覆盖Swift的高级运算符,以及如何定义你自己的运算符,或者为你自定义的类实现标准库中的运算符。
术语(Terminology)
运算符分为一元运算符,二元运算符,和三元运算符:
一元运算符作用在一个单独的目标上,比如(-a)。一元的前缀运算符紧跟在要操作的目标之前(!b)。一元的后缀运算符紧跟在要操作的目标之后(c!)。
二元运算符作用在2个目标上,比如2 + 3。被称为中缀,因为它出现在2个目标之间。
三元运算符作用在3个目标之上。和C语言一样,Swift只有一个三元运算符,也就是三目运算符(a ? b : c)
运算符操作的值叫做运算单元。在表达式1 + 2中,+ 号运算符是一个2元运算符,它的2个运算单元是值1和2。
赋值运算符(Assignment Operator)
赋值运算符(a = b)用来使用b的值初始化或者更新a的值。
let b = 10
var a = 5
a = b
// a 现在等于 10
如果赋值运算符右边是一个包含了多个值的元组,它的元素可以通过一次操作分出多个常量或者变量。
let (x, y) = (1, 2) // x 等于 1, y 等于 2”
和C语言以及OC中不一样,Swift中的赋值运算符本身不会有返回值,所以下面的语句是无效的:
if x = y {
// 无效, 因为 x = y 没有返回值.
}
这种特性可以防止赋值运算符和相等比较运算符(==)之间的误用。通过是if x = y 无效,Swift可以防止在你的代码中出现错误。
术数运算符(Arithmetic Operators)
Swift为所有数字类型支持了4个基本的术数运算符:
加法运算符(+) 1 + 2 // 3
减法运算符(-) 5 - 3 // 2
乘法运算符(*) 2 * 3 // 6
除法运算符(/) 10.0 / 2.5 // 4.0
和C语言和OC中的术数运算运算符不一样,Swift中的术数运算符默认不允许值溢出。可以使用Swift中值溢出运算符来选择值溢出的行为。
加法运算符也要支持字符串的连接:
“hello, " + "world" // 等于 "hello, world”
取余运算符(Remainder Operator)
取余运算符(a % b)计算出a里面可以包含多少个b,然后返回剩下的值,也就是余数。
NOTE:取余运算符(%)在其他语言中也被称为模运算符。然而严格来说,它是一个取余操作而不是取模操作。
9里面有2个4,所以余数是1。在Swift中,可以写成: 9 % 4
取余运算符使用下面的等式并且返回余数作为输出,来决定 a % b 的结果:
a = (b x someMultiplier) + remainder
其中someMultiplier是a中可以有的最大的b的个数,把9和4代入这个等式:
9 = (4 x 2) + 1
计算负数的时候使用的是同样的计算公式:
-9 % 4 // -1
把-9和4插入到上述的等式中:
-9 = (4 x -2) + -1
可以得到余数的值是-1
在公式中负数 b 的符号会被忽略。这就意味着 a % b 和 a % -b 的结果总是一样的。
一元减法运算符(-)
数值可以使用前缀(-),也就是一元减法运算符:
let three = 3
let minusThree = -three // -3
let plusThree = -minusThree // 3
一元减法运算符需要直接添加在需要操作的值前面,不需要有空格。
一元加法运算符(+)
一元加法运算符直接返回它操作的值,不做任何改变:
let minusSix = -6
let alsoMinusSix = +minusSix // -6
虽然一元加法运算符并不做任何事情,但是你可以在一些使用了一元减法运算符的代码中使用一元加法运算符来保持代码的对称。
符合赋值运算符(Compound Assignment Operators)
和C语言一样,Swift提供了混合赋值运算符,也就是赋值运算符和其他运算符组合使用。一个例子就是加法混合运算符(+=):
var a = 1 ; a += 2 // a 等于 3
表达式 a += 2 是 a = a + 2 的简写。为了更高的效率,加法运算符和复制运算符被组合在成一个运算符,一次执行了2个任务。
NOTE:混合运算符没有返回值,比如, let b = a += 2 是不对的。
比较运算符
Swift提供了标准C语言所有的比较运算符:
等于 (a == b) 不等于 (a != b)
大于 (a > b) 小于 (a < b)
大于等于 to (a >= b) 小于等于 (a <= b)
NOTE:Swift还提供了2个恒等运算符(===和!==),可以用来测试2个对象的引用是不是引用于同一个对象的实例。
每一个比较运算符返回一个布尔值来表明表达式是不是成立。
比较运算符通常会用在条件语句中,比如if语句:
let name = "world"
if name == "world" {
print("hello, world")
} else {
print("I'm sorry \(name), but I don't recognize you")
}
// 打印 "hello, world", because name 等于 "world"
如果2个元组有相同的类型,也可以用比较运算符比较。元组从左至右进行比较,一次比较一个值,直到比较结果不相等。两个对应的值的比较,会决定整个元祖的比较的结果。如果所有的元素都相等,那么元祖就是相等的,比如:
(1, "zebra") < (2, "apple") // true 因为 1 小于 2 ,后面的不比较
(3, "apple") < (3, "bird") // true 因为3 等于 3, "apple" 小于 "bird"
(4, "dog") == (4, "dog") // true 因为 4 等于 4, and "dog" 等于 "dog”
上面的例子中,可以看见第一行从左往右进行比较,因为1小于2,元组(1, "zebra")就被认为小于元组(2, "apple"),无论元组中的其他值是什么。不会去考虑"zebra"并不小于"apple",因为第一个元素的的比较已经决定了比较结果。然而,当第一个元素比较结果相等的话,第二个元素就会被拿来比较,第二行和第三行就是这样子做的。
只有在运算符适用于元祖的每一个元素,元组才可以比较。比如下面的例子,可以比较 (String, Int)类型的元组,因为String和Int都可以用 < 运算符比较。相对的,(String, Bool)类型的元组就不可以用 < 运算符比较,因为布尔值不可以使用< 运算符。
("blue", -1) < ("purple", 1) // OK, evaluates to true
("blue", false) < ("purple", true) // 错误,小于运算符不适用于布尔值
NOTE:Swift标准库实现的元祖比较符只支持元素个数小于7个的元素。如果希望比较7个或者更多的元素的元组,你需要自己实现比较运算符。
三元条件运算符(Ternary Conditional Operator)
三元条件运算符是一个包括了三个部分的特殊的元素的特殊的运算符,就像这样: question ? answer1 : answer2
这是一种简洁代码的方式,它根据question的结果去决定是执行answer1还是answer2,如果question的结果是true,会执行并返回answer1的返回值,如果question的结果是false,会执行并返回answer2的返回值。
三元条件运算符是下面代码的简写:
if question {
answer1
} else {
answer2
}
在有2个表达式需要考虑的情况下,三木运算提供了非常有效的简写方式。然而,请谨慎使用三木运算,它很简洁,但是过度使用付出的代价是难以阅读。在一些混合语句中尽量避免使用三木运算。
空合运算符(Nil-Coalescing Operator)
空合运算符(a ?? b),如果可选值a有值,解包a并且返回a解包后的值,如果a没有值,返回默认值b。表达式中的a是一个可选值,b和a解包后的值的类型一样。
空合运算符下面代码的简写:
a != nil ? a! : b // ( a != nil)中 != 是一个整体, 而不是 a!是一个整体!!
上面的代码使用了三目运算符和强制解包去访问a中包含的值,当a是nil的时候就返回b。空合运算符以一种优雅的方式,使得条件判断和解包的操作可以用更精简和易读的形式组合在了一起。
NOTE:如果a的值不是nil,b的值不会被求值。也就是所谓的短路求值。
下面的例子使用空合运算符在默认的颜色和用户定义的颜色之间做选择:
let defaultColorName = "red"
var userDefinedColorName: String? // 默认是nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, 所以使用默认值 defaultColorName "red"
变量userDefinedColorName被定义为可选的String类型,默认是nil。因为userDefinedColorName是可选值,所以可以在考虑它的值的时候使用空合运算。上面的例子中,空合运算是为了决定变量colorNameToUse的初始值,因为userDefinedColorName是nil,表示式userDefinedColorName ?? defaultColorName返回defaultColorName的值,也就是"red"。
如果给可选变量userDefinedColorName赋予一个非空的值,然后再执行空合运算,将不会返回默认值,而是返回userDefinedColorName中包含的值。
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 不是 nil, 所以colorNameToUse现在是"green"