运算符是用于检查、更改或组合值的特殊符号或短语。例如,加法运算符(+)添加两个数字,如let i = 1 + 2,逻辑运算符(&&)组合两个布尔值,如if enteredDoorCode && passedRetinaScan。
Swift支持大多数标准的C操作符,并改进了一些功能来消除常见的编码错误。赋值运算符(=)不返回值,以防止在使用equal to运算符(==)时错误地使用它。算术运算符(+、-、*、/、%等)检测和禁止值溢出,以避免在处理大于或小于存储它们的类型的允许值范围的数字时出现意外结果。您可以选择使用Swift的溢出操作符来评估溢出行为,如Overflow Operators中所述。
Swift还提供了C语言中没有的范围操作符,比如a..< b和a…作为表示值范围的快捷方式。
本章描述了Swift中的常用操作符。
Advanced Operators 包括Swift的高级运算符,并描述如何定义您自己的自定义运算符,以及为您自己的自定义类型实现标准运算符。
Terminology 术语
运算符有一元、二元或三元:
- 一元运算符只操作一个目标(例如-a)。一元前缀操作符紧接在目标的前面(如!b),一元后缀操作符紧接在目标的后面(如c!)。
- 二进制操作符操作两个目标(例如2 + 3),并且是中缀,因为它们出现在两个目标之间。
- 三元操作符操作三个目标。和C语言一样,Swift只有一个三元运算符,即三元条件运算符(a ?b: c)。
操作符影响的值是操作数。在表达式1 + 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和Objective-C中的赋值操作符不同,Swift中的赋值操作符本身并不返回值。下列陈述无效:
if x = y {
...
}
该特性可以防止在实际使用等于操作符(==)时意外使用赋值操作符(=)。通过使if x = y无效,Swift可以帮助您避免代码中的此类错误。
Arithmetic Operators 算数运算符
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"
Remainder Operator 余数运算符
余数运算符(a % b)计算出b在a中的倍数,并返回剩余的值(称为余数)。
注意:余数运算符(%)在其他语言中也称为模运算符。然而,它在负数中的Swift行为意味着,严格地说,它是余数,而不是模运算。
Unary Minus Operator 一元-操作符
数值的符号可以使用前缀-来切换,称为一元减运算符:
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元减号运算符(-)直接前缀在它所作用的值之前,没有任何空格。
Unary Plus Operator
一元+操作符
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
虽然一元加号运算符实际上什么都不做,但是当你对负数也使用一元减号运算符时,你可以用它在你的代码中为正数提供对称性。
复合赋值操作符
与C语言一样,Swift提供了将赋值(=)与另一个操作组合在一起的复合赋值操作符。一个例子是加法赋值运算符(+=):
var a = 1
a += 2
// a is now equal to 3
表达式a += 2是a = a + 2的简写。实际上,加法和赋值被合并到一个操作符中,该操作符同时执行两个任务。
注意:复合赋值操作符不返回值。例如,你不能让b = a += 2。
有关Swift标准库提供的操作符的信息,请阅读 Operator Declarations。
Comparison Operators 比较运算符
- 等于 (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".
如果两个元组具有相同的类型和相同数量的值,则可以对它们进行比较。从左到右比较元组,每次一个值,直到比较发现两个不相等的值。比较这两个值,比较的结果决定了元组比较的总体结果。如果所有元素都相等,那么元组本身也是相等的。例如:
(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"
只有当操作符可以应用于各自元组中的每个值时,才可以将元组与给定的操作符进行比较。例如,如下面的代码所示,您可以比较类型(String, Int)的两个元组,因为可以使用<操作符比较String和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个元素的元组比较,如果你的元组元素大于等于7,需要比较时,您必须自己实现比较操作符。
Ternary Conditional Operator 三元条件运算符
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
第一个例子使用三元条件运算符意味着rowHeight可以在一行代码中设置为正确的值,这比第二个例子中使用的代码更简洁。
三元条件运算符为决定要考虑哪一个表达式提供了一种有效的简写。但是,要小心使用三元条件运算符。如果过度使用,它的简洁性可能导致难以阅读的代码。避免将三元条件运算符的多个实例合并到一个复合语句中。
Nil-Coalescing Operator nil 聚合运算符
nil 聚合运算符 (a ?? b) 如果可选类型a有一个值,那么将其展开值返回,如果a为nil则返回b,表达式a总是可选类型。表达式b必须匹配存储在a中的类型。
nil 聚合运算符是以下代码的缩写:
a != nil ? a! : b
注意 : 如果a的值是非nil的,则不计算b的值。这就是所谓的短路计算。
下面的例子使用nil 聚合运算符在默认颜色名和可选的用户定义颜色名之间进行选择:
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-coalescing操作符检查,则使用包装在userDefinedColorName中的值,而不是默认值:
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is not nil, so colorNameToUse is set to "green"
Range Operators 区间运算符
Swift包含几个范围操作符,它们是表示值范围的快捷方式。
Closed Range Operator 闭区间运算符
闭区间运算符(a…b)定义了一个从a到b的范围,包括值a和b。a的值不能大于b。
闭区间运算符在遍历希望使用所有值的范围时非常有用,例如for-in循环:
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
Half-Open Range Operator 半开区间运算符
半开区间运算符(a..<b) 与闭区间运算符一样,a的值不能大于b。如果a的值等于b,那么得到的值域将是空的。
半开区间运算符在处理从零开始的列表(如数组)时特别有用,在数组中计算列表的长度(但不包括)非常有用:
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开始的。
One-Sided Ranges 单边区间运算符
区间一遍有限制,另一边达到所有符合的值。
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
Logical Operators 逻辑运算符
逻辑运算符修改或组合布尔逻辑值true和false。Swift支持基于c语言的三种标准逻辑操作符:
- 逻辑非(!a)
- 逻辑与 (a && b) a和b同时为true,才返回true
- 逻辑或 (a || b) 或者,只要一个满足,就返回true
逻辑非运算符
逻辑NOT操作符是一个前缀操作符,它出现在它操作的值之前,没有任何空格。如下例所示:
let allowedEntry = false
if !allowedEntry {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
逻辑与 运算符
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
逻辑或 运算符
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
组合逻辑运算符
您可以组合多个逻辑运算符来创建更长的复合表达式:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
注意:Swift逻辑运算符&&和||是左关联的,这意味着具有多个逻辑运算符的复合表达式首先计算最左边的子表达式。
Explicit Parentheses 明确的括号
有时候,在不严格需要括号的情况下,添加括号是很有用的,这样可以使复杂表达式的意图更易于阅读。在上面的door access例子中,在复合表达式的第一部分添加括号是很有用的,可以使其意图显式:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
圆括号清楚地表明,前两个值被认为是整个逻辑中独立的可能状态的一部分。复合表达式的输出没有变化,但是总体意图对读者来说更清晰。可读性总是优先于简洁;用括号来帮助你明确你的意图。
网友评论