引言
继续学习Swift文档,从上一章节:基础,我们学习了Swift基础,现在,我们学习Swift的基本操作。这一章节的内容比较简单,一些运算符操作基本上和C、OC上的一样,不过在Swift上也有它特有的一些运算符,可以简化代码,如??操作符、...操作符、..<操作符和单边值域,不熟悉的朋友可以单独去看这部分内容(在7、8、9三个小节),其他的运算符就可以跳过了。由于篇幅较长,这里分篇来记录,接下来,开始吧!
基本的操作
运算符是用于检查、更改或组合值的特殊符号或短语。例如,加法运算符(+)将两个数字相加,如let i = 1 + 2;逻辑和运算符(&&)组合两个布尔值,如if enteredDoorCode && passedRetinaScan。
Swift支持大多数标准的C操作符,并改进了一些功能,以消除常见的编码错误。赋值操作符(=)不返回值,以防止在使用equal to操作符(==)时错误地使用它。算术运算符(+、-、*、/、%等等)检测并禁止值溢出,以避免在处理大于或小于存储它们的类型允许的值范围的数字时出现意外结果。您可以使用Swift的溢出操作符(如溢出操作符中所述)来选择对溢出行为进行值设置。
Swift还提供了C中没有的范围操作符,比如a..< b和a…b作为表示值范围的快捷方式。
本章介绍了Swift中常用的操作符。高级操作符涵盖Swift的操作符,并描述如何定义您自己自定义操作符和实现标准操作符为您自己自定义类型。
1 术语
运算符有一元、二元或三元:
- 一元操作符对单个目标(比如-a)进行操作。一元前缀操作符立即出现在它们的目标(比如!b)之前,一元后缀操作符立即出现在它们的目标(比如c!)之后。
- 二元操作符对两个目标(例如2 + 3)进行操作,并且是中缀,因为它们出现在两个目标之间。
- 三元运算符对三个目标进行操作。和C一样,Swift只有一个三元运算符,三元条件运算符(a ? b : c)。
操作符影响的值是操作数。在表达式1 + 2中,+符号是一个二元运算符,它的两个操作数是值1和2。
2 赋值运算符
赋值操作符(a = b)初始化或更新a的值为b:
let b = 10
var a = 5
a = b
// a is now equal to 10
如果赋值的右边是一个有多个值的元组,那么它的元素可以一次分解为多个常量或变量:
let (x, y) = (1, 2)
// x is equal to 1, and y is equal to 2
与C和Objective-C中的赋值操作符不同,Swift中的赋值操作符本身不返回值。以下陈述无效:
if x = y {
// This is not valid, because x = y does not return a value.
}
该特性防止在实际使用equal to操作符(==)时意外使用赋值操作符(=)。通过设置if x = y无效,Swift可以帮助您避免代码中出现这类错误。
3 算术运算符
针对数值类型,Swift提供了四种基本的算术运算符:
- 加法(+)
- 减法(-)
- 乘法 (*)
- 除法 (/)
1 + 2 // equals 3
5 - 3 // equals 2
2 * 3 // equals 6
10.0 / 2.5 // equals 4.0
与C和Objective-C中的算术运算符不同,Swift算术运算符默认不允许值溢出。您可以选择使用Swift的溢出操作符(如a &+ b)来计算溢出行为的值。请参阅溢出操作符。
字符串连接也支持加法运算符:
"hello, " + "world" // equals "hello, world"
3.1 余数操作符
余数运算符(a % b)计算出a中可以容纳多少个b的倍数,并返回剩余的值(称为余数)。
注意
余数运算符(%)在其他语言中也称为模运算符。但是,它在负数中的表现意味着,严格地说,它是一个余数而不是模运算。
下面是余数运算符的工作原理。要计算9 % 4,你首先要算出9能装下多少个4s:
../_images/remainderInteger_2x.png
可以在9中放入两个4s,余数为1(用橙色表示)。
在Swift中可以这样写:
9 % 4 // equals 1
为了确定a % b的答案,%运算符计算以下等式并返回余数作为输出:
a = (b x some multiplier) + remainder
some multiplier是a中b的最大倍数。
将9和4插入到这个方程,得到:
9 = (4 x 2) + 1
计算a的负值的余数时采用相同的方法:
-9 % 4 // equals -1
将-9和4插入方程,得到:
-9 = (4 x -2) + -1
余数为-1。
当b为负值时,b的符号被忽略。这意味着a % b和a % -b总是给出相同的答案。
3.2 一元减(-)操作符
数字值的符号可以通过前缀-来进行切换,也就是一元减运算符:
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元减运算符(-)直接放在它所操作的值前面,没有任何空格。
3.3 一元加(+)操作符
一元加号运算符(+)只返回它所操作的值,没有任何变化:
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
虽然一元加号运算符实际上没有任何作用,但是您可以在代码中使用它来为正数提供对称,同时也可以使用一元减号运算符来为负数提供对称。
4 复合赋值操作符
像C一样,Swift提供了将赋值(=)与另一个操作组合起来的复合赋值操作符。一个例子是加法赋值操作符(+=):
var a = 1
a += 2
// a is now equal to 3
表达式a += 2是a = a + 2的简写。有效地,加法和赋值被合并到一个运算符中,同时执行两个任务。
注意
复合赋值操作符不返回值。例如,你不能写b = a += 2。
有关Swift标准库提供的操作符的信息,请参见操作符声明。
5 比较运算符
Swift支持所有标准C比较运算符:
- 等于(a == b)
- 不等于(a != b)
- 大于(a > b)
- 小于(a < b)
- 大于等于(a >= b)
- 小于等于(a <= b)
注意
Swift还提供了两个身份操作符(===和!==),用于测试两个对象引用是否都引用同一个对象实例。有关更多信息,请参见标识操作符。
每个比较运算符都返回一个Bool值来表示语句是否为真:
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
比较运算符常用于条件语句中,如if语句:
let name = "world"
if name == "world" {
print("hello, world")
} else {
print("I'm sorry \(name), but I don't recognize you")
}
// Prints "hello, world", because name is indeed equal to "world".
有关If更多内容,请参阅控制流。
如果两个元组具有相同的类型和相同数量的值,则可以比较它们。元组从左到右进行比较,一次一个值,直到比较发现两个不相等的值为止。比较这两个值,比较的结果决定元组比较的总体结果。如果所有元素都相等,则元组本身也相等。例如:
(1, "zebra") < (2, "apple") // true because 1 is less than 2; "zebra" and "apple" are not compared
(3, "apple") < (3, "bird") // true because 3 is equal to 3, and "apple" is less than "bird"
(4, "dog") == (4, "dog") // true because 4 is equal to 4, and "dog" is equal to "dog"
在上面的示例中,您可以在第一行看到从左到右的比较行为。因为1小于2,所以(1,“zebra”)被认为小于(2,“apple”),而与元组中的其他值无关。“zebra”不小于“apple”并不重要,因为比较已经由元组的第一个元素决定了。但是,当元组的第一个元素相同时,将比较它们的第二个元素—这是在第二和第三行发生的事情。
只有当运算符可以应用于相应元组中的每个值时,才能将元组与给定的运算符进行比较。例如,如下面的代码所示,您可以比较类型(String, Int)的两个元组,因为字符串和Int值都可以使用<操作符进行比较。相反,类型的两个元组(String、Bool)不能与<操作符进行比较,因为<操作符不能应用于Bool值。
("blue", -1) < ("purple", 1) // OK, evaluates to true
("blue", false) < ("purple", true) // Error because < can't compare Boolean values
注意
Swift标准库包含元组比较运算符,用于元素少于七个的元组。要比较具有7个或更多元素的元组,必须自己实现比较运算符。
6 元条件运算符
三元条件运算符是一种特殊的运算符,由三部分组成:question ?answer1 : answer2。这是一个计算两个表达式中的一个的捷径,基于问题是真的还是假的。如果question为真,它计算answer1并返回它的值;否则,它将计算answer2并返回其值。
三元条件运算符是以下代码的简写:
if question {
answer1
} else {
answer2
}
下面是一个示例,它计算表行的高度。如果行有标题,行高应该比内容高50点,如果行没有标题,行高20点:
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight is equal to 90
上面代码是下面代码的简写:
let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
rowHeight = contentHeight + 50
} else {
rowHeight = contentHeight + 20
}
// rowHeight is equal to 90
第一个示例使用了三元条件运算符,这意味着可以在一行代码中将rowh8设置为正确的值,这比第二个示例中使用的代码更简洁。
三元条件运算符提供了一种有效的简写方式来决定两个表达式中的哪一个要考虑。但是,使用三元条件运算符时要小心。如果过度使用,它的简洁性会导致难以阅读的代码。避免将三元条件运算符的多个实例组合成一个复合语句。
7 Nil-Coalescing操作符( ??操作符 )
nil-coalescing操作符(a ?? b)如果一个可选的a包含一个值,则展开它;如果a为nil,则返回一个默认值b。表达式a始终是可选类型。表达式b必须匹配存储在a中的类型。
Nil-Coalescing操作符是下面代码的简写:
a != nil ? a! : b
上面的代码使用三元条件运算符和强制展开(a!),当a不是nil时访问包装在a中的值,否则返回b。nil-coalescing操作符提供了一种更优雅的方式,以简洁和可读的形式封装这种条件检查和展开。
注意
如果a的值是非nil,那么b的值就不会被计算。这就是所谓的短路评估。
下面的例子使用了nil-coalescing操作符来选择默认的颜色名称和可选的用户定义的颜色名称:
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
userDefinedColorName变量被定义为一个可选字符串,默认值为nil。因为userDefinedColorName是可选类型,所以可以使用nil-coalescing操作符来考虑它的值。在上面的示例中,操作符用于确定名为colorNameToUse的字符串变量的初始值。因为userDefinedColorName是nil,表达式userDefinedColorName ??defaultColorName返回defaultColorName的值,或者“red”。
如果你给userDefinedColorName分配一个非nil值,并再次执行nl -coalescing操作符检查,userDefinedColorName内的值将被使用,而不是默认值:
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is not nil, so colorNameToUse is set to "green"
8 范围操作符
Swift包括几个范围操作符,它们是表示值范围的快捷方式。
8.1 封闭范围运算符 ( ... 操作符 )
闭值域运算(a…b)定义了从a到b的值域,包括a和b的值。a的值不能大于b。
闭合范围运算符在迭代一个范围时非常有用,在这个范围内你需要使用所有的值,例如forin循环:
for index in 1...5 {
print("\(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
关于更多for-in循环,参阅控制流。
8.2 半开范围操作符( ..< 操作符)
半开区间运算符(a..<b)定义了从a到b的范围,但不包括b。之所以称之为半开区间,是因为它包含了第一个值,但没有包含最终值。与封闭范围操作符一样,a的值不能大于b。如果a的值等于b,那么结果范围将为空。
当你处理基于0的列表(比如数组)时,半开的范围特别有用,这里有用的是计算列表的长度(但不包括):
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("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
注意,数组包含4个项,但是0..<count只计算到3(数组中最后一项的索引),因为它是半开放的范围。有关数组的更多信息,请参见数组。
8.3 单边值域
对于在一个方向上尽可能连续的范围,封闭范围操作符有另一种形式—例如,包含数组从索引2到数组末尾的所有元素的范围。在这些情况下,可以忽略范围操作符一侧的值。这种值域称为单边值域,因为运算符只有一边有值。例如:
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian
半开式值域运算符也有一个单边形式,只有它的最终值。就像在两边都包含值一样,最终值也不属于范围内。例如:
for name in names[..<2] {
print(name)
}
// Anna
// Alex
单边值域可以在其他上下文中使用,而不仅仅是下标。您不能遍历遗漏第一个值的单边值域,因为不清楚迭代应该从哪里开始。您可以迭代一个单边的值域,省略其最终值;但是,由于范围是无限延续的,所以请确保为循环添加了一个显式的结束条件。还可以检查单边值域是否包含特定值,如下面的代码所示。
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
9 逻辑运算符
逻辑运算符修改或组合布尔逻辑值true和false。Swift支持基于c语言的三种标准逻辑运算符:
- 逻辑 非 (!a)
- 逻辑 与 (a && b)
- 逻辑 或 (a || b)
9.1 逻辑非运算符
逻辑非操作符(!a)反转布尔值,使真变为假,假变为真。
逻辑非操作符是一个前缀操作符,它出现在它所操作的值的前面,没有任何空格。可以理解为“非 a”,如下例所示:
let allowedEntry = false
if !allowedEntry {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
“if !allowedEntry”可以理解为“if not allowed entry”。后面的行只在“not allowed entry”为真时执行;也就是说,如果allowedEntry为false。
与本例一样,谨慎选择布尔常量和变量名有助于保持代码可读性和简洁,同时避免双重否定或逻辑语句混乱。
9.2 逻辑与运算符
逻辑和运算符(a && b)创建逻辑表达式,其中两个值必须为真,整个表达式也为真。
如果任一值为假,则整个表达式也为假。事实上,如果第一个值为假,第二个值甚至不会计算,因为它不可能使整个表达式等于真。这就是所谓的短路评估。
这个例子考虑了两个Bool值,只有当两个值都为真时才允许访问:
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
9.3 逻辑或运算符
逻辑或操作符(|| b)是由两个相邻管道字符组成的中缀操作符。您可以使用它来创建逻辑表达式,其中两个值中只有一个必须为真才能使整个表达式为真。
与上面的逻辑和运算符一样,逻辑或运算符使用短路求值来考虑其表达式。如果逻辑或表达式的左边为真,则不计算右边的值,因为它不能改变整个表达式的结果。
在下例中,第一个Bool值(hasDoorKey)为假,但第二个值(knowsOverridePassword)为真。因为一个值为真,整个表达式的计算结果也为真,因此允许访问:
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
9.4 组合的逻辑运算符
您可以组合多个逻辑运算符来创建更长的复合表达式:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
这个示例使用多个&&和||操作符创建一个更长的复合表达式。但是,&&和||操作符仍然只对两个值进行操作,因此这实际上是三个连接在一起的较小的表达式。这个例子可以理解为:
如果我们输入了正确的门码并且通过了视网膜扫描,或者如果我们有一个有效的门钥匙,或者如果我们知道紧急控制密码,那么就允许进入。
根据enteredDoorCode、passedRetinaScan和hasDoorKey的值,前两个子表达式为false。但是,紧急覆盖密码是已知的,因此整个复合表达式的计算结果仍然为true。
注意
Swift逻辑运算符&&和||是左关联的,这意味着包含多个逻辑运算符的复合表达式首先计算最左边的子表达式。
9.5 用括号分隔多个逻辑运算符
有时,如果不是严格需要括号,那么包含括号是很有用的,这样可以使复杂表达式的意图更容易理解。在上面的door access示例中,在复合表达式的第一部分周围添加括号以明确其意图是很有用的:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
括号清楚地表明前两个值被视为整个逻辑中单独可能的状态的一部分。复合表达式的输出没有变化,但总体意图对读者更清晰。可读性总是比简洁更重要;使用括号来帮助明确你的意图。
总结
这一章节的内容比较简单,一些运算符操作基本上和C、OC上的一样,不过在Swift上也有它特有的一些运算符,可以简化代码,如下所示:
- ?? 操作符
- 封闭范围操作符(...) 、半开范围操作符(..<) 和单边值域
具体的作用,可以翻看上面的内容找到答案。
最后,喜欢的朋友可以打个star哦!这样我才更有动力继续下去,嘎嘎嘎~
网友评论