原文链接:http://www.ioswift.org/
6.基本操作
运算符是一种用来检查,改变,或组合值的特殊的符号或短语。例如,+ 将两个数相加(let i = 1 + 2)。更复杂的运行算,如逻辑与运算符 &&(如 if enteredDoorCode && passedRetinaScan),或者 让 i 便捷加 1 的运算符自增运算符 ++i 等。
Swift 支持大多数 C 语言的运算,并改进了一些特性来消除常见的编码错误。赋值运算符( = )没有返回值,以防止它被误用为等于运算符( = = )。算术运算符(+、-、*、/、%等等)会自动检测以防止溢出,避免由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然你可以使用 Swift 的溢出运算符来实现溢出。
与 C 语言不同的是,Swift 可以对浮点数进行取余运算(%),Swift 还提供了表达两数之间的值的区间运算符:a..b 和 a...b ,方便表达一个区间内的数值。
本章节只描述了 Swift 的基本运算符,高级运算符包含了高级运算符,以及如何自定义运算符和运算符重载。
6.1.术语
运算符有一元,二元和三元运算符。
一元运算符只操作一个对象(如-a)。一元运算符分前置和后置,前置运算符排在操作对象之前(如!b),后置运算符需排在操作对象之后(如i++)。
二元运算符操作两个对象(如2 + 3),二元运算符都是中置的,因为它出现在两个操作对象之间。
三元运算符操作三个对象,和 C 语言一样,Swift 只有一个三元运算符,就是三元条件运算符(a ? b : c)。
运算符操作的对象叫操作数,在表达式 1 + 2 中,加号 + 是二元运算符,它的两个操作数是 1 和 2。
6.2.赋值运算符
赋值运算 = 。比如:a = b ,表示用 b 的值来初始化或更新 a 的值:
var a = 5
a = b
// a is now equal to 10
如果 + 右侧是一个元组或多个值,它的元素会被分解成多个常量或变量:
// x is equal to 1, and y is equal to 2
与 C 和 Objective - C 的赋值运算符不同,Swift 的赋值运算符没有返回值。所以下面的代码是错误的:
// this is not valid, because x = y does not return a value
}
这个功能可以防止赋值运算符 (=) 被用作逻辑相等运算符 (= =)。if x = y 是无效的,Swift 从底层帮你避免了这些代码错误。
6.3.算数运算符
Swift 对所有数值类型都支持基本的四则运算:
加法(+)
减法(-)
乘法(*)
除法(/)
5 - 3 // equals 2
2 * 3 // equals 6
10.0 / 2.5 // equals 4.0
与 C 和 Objective-C 不同的是,Swift 不允许在数值运算中出现溢出。但你可以使用 Swift 的溢出运算符来达到你有目的的溢出(如a &+ b)。
加法运算符也用于 String 的连接:
两个 Character 值或一个 String 和一个 Character 值相加会生成一个新的 String 值:
let cow: Character = "c"
let dogCow = dog + cow
// dogCow is equal to "dc"
6.4.取余运算符
取余运算(a % b)就是我们数学中的求余数运算。
注意:取余运算(%)在其他语言中也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"取余"比"取模"更合适些。
来看一个取余的例子,计算9 % 4:
9是4的2倍,余数是1(用橙色标出)。
在 Swift 中这么写:
为了得到a % b的结果,% 计算了以下等式,并输出余数作为结果:
当倍数取最大值的时候,适合在a中。把9和4代入等式中,我们得 1:
同样的方法,我来们计算 -9 % 4:
在对负数 b 求余时,b 的符号会被忽略。所以 a % b 和 a % -b的结果是相同的。
6.5.浮点数取余计算
不同于 C 和 Objective-C,Swift 中是可以对浮点数进行取余。
这个例子中,8 除以 2.5 等于 3 余 0.5,所以结果是 Double 类型的值 0.5 。
6.6.自增和自减运算符
和 C 一样,Swift 提供了对变量本身加1或减1的自增(++)和自减(--)的运算符。其操作对象可以是整型和浮点型。
++i // i now equals 1
每调用一次 ++i ,i 的值就会加 1 。实际上,++i 是 i = i + 1 的简写,而 --i 是 i = i - 1 的简写。
++ 和 -- 既是前置又是后置运算。++i ,i ++,--i 和 i-- 都是有效的写法。
需要注意的是这些运算符修改了 i 后有一个返回值。如果只想修改 i 的值,可以忽略返回值。如果想使用返回值,你就需要注意前置和后置操作对应的返回值是不同的。
当 ++ 前置的时候,先自増再返回。
当 ++ 后置的时候,先返回再自增。
如:
let b = ++a
// a and b are now both equal to 1
let c = a++
// a is now equal to 2, but c has been set to the pre-increment value of 1
上述例子中,let b = ++a 先把 a 加 1 了再返回 a 的值。所以 a 和 b 都是新值 1。
而 let c = a++,是先返回了 a 的值,然后 a 才加 1。所以 c 得到了 a 的旧值 1 ,而 a 加 1 后变成 2 。
除非你需要使用 i++ 的特性,不然推荐你使用 ++i 和 --i ,因为先修改后返回这样的行为更符合我们的逻辑。
6.7.一元负号算符
数值的正负可以使用前缀(-)(即一元负号)来切换:
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元负号(-)写在操作数之前,中间没有空格。
6.8.一元正号算符
一元正号(+)返回不做任何改变的操作数的值。
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
虽然一元 + 做无用功,但当使用一元负号来表达负数时,同样使用一元正号来表达正数,这样你的代码会具有对称美。
6.9.复合赋值操作符
和 C 语言一样,Swift 也可以把其他运算符和赋值运算(=)一起组合使用,即是:复合赋值运算符。加赋运算符(+=)就是其中一个例子
a += 2
// a is now equal to 3
表达式 a += 2 是 a = a + 2 的简写,一个加赋运算同时把加法和赋值两件事完成了。
注意:复合赋值运算没有返回值,let b = a += 2 代码是错误。这不同于上面提到的自增和自减运算符。
6.10.比较运算符
Swift 支持所有标准 C 语言中的比较运算符
不等于(a != b)
大于(a > b)
小于(a < b)
大于等于(a >= b)
小于等于(a <= b)
注意:Swift 也提供恒等 === 和不恒等 !== 这两个比较符来判断两个对象是否引用同一个对象实例。
每个比较运算都返回了一个布尔值:
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
比较运算多用于条件语句,如if条件:
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"
6.11.三元条件运算符
三元条件运算符比较特殊,它有三个操作数,它的格式是 question ? answer1 : answer2 。简洁的表达出 question 是否成立( true )。如果 question 成立,返回 answer1 的结果,否则返回 answer2 的结果。
使用三元条件运算简化了以下代码:
answer1
} else {
answer2
}
来看个例子,计算表格行高:如果有表头,那行高是内容高度增加50像素; 否则增加20像素。
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight is equal to 90
上面的代码比下面的代码更简洁:
let hasHeader = true
var rowHeight = contentHeight
if hasHeader {
rowHeight = rowHeight + 50
} else {
rowHeight = rowHeight + 20
}
// rowHeight is equal to 90
第一段代码使用了三元条件运算符,只要一行代码就可以得到答案,比第二段代码简洁很多。无需 rowHeight 变量,因为在if语句中它的值不需要改变。
三元条件运算符更有效率、更便捷地表达了二选一的选择。注意,过度使用三元条件运算会使代码比较难懂,应避免在一条语句使用多个三元条件运算符。
6.12.区间运算符
6.13.闭区间运算符
闭区间运算符(a...b):包含从 a 到 b (包括 a 和 b )之间的所有的值。
闭区间运算符在迭代所有值的时候非常有用,比如在 for-in 循环中:
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
6.14.半闭区间运算符
半闭区间运算符(a..b):定包含从 a 到 b 但不包括 b 的区间内的所有的值。
被称为半闭区间,是因为该区间包含第一个值,不包括最后一个值。
半闭区间主要用于从 0 开始的列表(如数组),可以方便地取值从 0 到列表的长度(但不包括)。
6.15.逻辑运算符
逻辑非( !a )
逻辑与( a && b )
逻辑或( a || b )
6.16.逻辑非运算符
逻辑非运算符( !a ):对一个布尔值取反,也就是 true 变成 false ,false 变成 true。
它是一个前置运算符,必须在操作数之前,且中间不能有空格。读作 非a ,看下面的例子:
if !allowedEntry {
println("ACCESS DENIED")
}
// prints "ACCESS DENIED"
if !allowedEntry 语句可以读作 “ 如果 非allowedEntry ”。
如果“ 非allowedEntry ”为true,即 allowEntry 为 false 时,执行中括号中代码。
小心地使用布尔常量或变量有助于代码的可读性,尽量避免使用双重或混乱的逻辑非运算语句。
6.17.逻辑与运算符
逻辑与运算符(a && b):当 a 和 b 的值都为 true 时,整个表达式的值为 true。
只要任意一个值为 false ,整个表达式的值就为 false。事实上,如果第一个值为 false,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做 "短路计算(short-circuit evaluation)"。
下面的例子,只有两个 Bool 值都为 true 值的时候才允许访问:
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
println("Welcome! ")
} else {
println("ACCESS DENIED")
}
// prints "ACCESS DENIED"
6.18.逻辑或运算符
逻辑或运算符(a || b):当 a 和 b 中其中一个为 true 时,整个表达式就为true。
同逻辑与一样,逻辑或也是“短路计算”,当左侧的表达式为 true 时,将不再计算右侧的表达式,因为它不可能改变整个表达式的值。
下面例子中,第一个布尔值 hasDoorKey 为false,但第二个值 knowsOverridePassword 为true,所以整个表达是true,于是允许访问:
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
println("Welcome! ")
} else {
println("ACCESS DENIED")
}
// prints "Welcome! "
6.19.组合逻辑运算符
我们可以组合多个逻辑运算来创建一个更长的复合逻辑运算:
println("Welcome! ")
} else {
println("ACCESS DENIED")
}
// prints "Welcome! "
这个例子使用了多个 && 和 || 创建了一个复合逻辑。但无论怎样,&& 和 || 始终只能操作两个值。所以这实际是三个简单的简单逻辑组成的操作。
它可以被理解为:如果有正确的进入门的代码并通过了视网膜扫描;或者有一把有效的钥匙;或者有紧急覆盖密码,那么就可以访问。
前两种情况都不满足,所以结果是 false,但是有紧急覆盖密码,所以整个复杂表达式的值还是 true。
6.20.使用括号明确优先级
为了使复杂表达式更容易读懂,可以在合适的地方使用括号(并非必要的)明确优先级。在上面的例子中,给第一个部分加个括号会使它看起来逻辑更清晰:
println("Welcome! ")
} else {
println("ACCESS DENIED")
}
// prints "Welcome! "
括号使得前两个值成为独立的一部分。虽然有无括号的结果是一样的,但有括号使代码更清晰。代码的可读性比简洁性更重要,所以括号有时候是必要的!