Swift5.4 语言指南(五) 基本运算符
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9720408.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
一个运营商是一个特殊的符号或短语,你用它来检查,更改或合并值。例如,加法运算符(+
)将两个数相加,如,而逻辑AND运算符()将两个布尔值相结合,如。let i = 1 + 2
&&
if enteredDoorCode && passedRetinaScan
Swift支持您可能已经从诸如C之类的语言中认识的运算符,并改进了一些功能来消除常见的编码错误。赋值运算符(=
)不会返回值,以防止在==
打算使用等于运算符()时错误地使用该值。算术运算符(+
,-
,*
,/
,%
等等)检测,并禁止值溢出,以避免意外的结果与成为小于该类型的所允许的值的范围,其存储他们更大或更小的数字工作时。您可以选择使用Swift的溢出运算符来评估溢出行为,如Overflow Operators中所述。
Swift还提供了C中找不到的范围运算符(例如a..<b
和a...b
)作为表示值范围的快捷方式。
本章介绍了Swift中的常见运算符。高级运算符涵盖了Swift的高级运算符,并描述了如何定义自己的自定义运算符以及如何为自己的自定义类型实现标准运算符。
术语
运算符是一元,二进制或三元运算符:
- 一元运算符针对单个目标(例如
-a
)进行操作。一元前缀运算符紧接在其目标(如!b
)之前,一元后缀运算符紧随其目标(如c!
)之后。 - 二进制运算符在两个目标(例如)上操作,并且是中缀的,因为它们出现在两个目标之间。
2 + 3
- 三元运算符针对三个目标进行操作。与C一样,Swift也只有一个三元运算符,即三元条件运算符()。
a ? b : c
运算符影响的值为操作数。在表达式中,符号是二进制运算符,其两个操作数是值和。1 + 2
+
1
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 isn't valid, because x = y doesn't return a value.
- }
此功能可防止在实际需要=
等于运算符(==
)时偶然使用赋值运算符()。通过使其无效,Swift可帮助您避免代码中的此类错误。if x = y
算术运算符
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
String
连接也支持加法运算符:
- "hello, " + "world" // equals "hello, world"
余数运算符
该余运算符()的作品如何的好几倍将适合的内部,并返回剩下的超所值(被称为剩余部分)。a % b
b
a
笔记
余数运算符(%
)在其他语言中也称为模运算符。但是,它在Swift中的负数行为意味着严格来说,这是余数而不是取模运算。
这就是余数运算符的工作方式。为了进行计算,您首先要计算出内部可以容纳多少个:9 % 4
4
9
![../_images/remainderInteger_2x.png](https://docs.swift.org/swift-book/_images/remainderInteger_2x.png)
您可以4
在内9
放两个,其余为1
(显示为橙色)。
在Swift中,这将写为:
- 9 % 4 // equals 1
为了确定的答案,运算符计算以下公式并返回作为其输出:a % b
%
remainder
a
=(b
x )+some multiplier
remainder
这里是倍数的数量最多,将适合里面。some multiplier
b
a
将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
一元减号
可以使用前缀-
(称为一元减运算符)来切换数值的符号:
- let three = 3
- let minusThree = -three // minusThree equals -3
- let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元减号(-
)紧接在其运算的值之前,没有任何空格。
一元加号运算符
在一元加运算(+
)只返回其所操作的价值,没有任何变化:
- 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
笔记
复合赋值运算符不返回值。例如,您不能编写。let b = a += 2
有关Swift标准库提供的运算符的信息,请参见运算符声明。
比较运算符
Swift支持以下比较运算符:
- 等于()
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 isn't 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 isn't 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" aren't 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)
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标准库包含用于少于七个元素的元组的元组比较运算符。要比较具有七个或更多元素的元组,必须自己实现比较运算符。
三元条件运算符
所述三元条件算子是由三个部分组成,这需要形式的特殊操作。这是根据是对还是错来评估两个表达式之一的捷径。如果为true,则评估并返回其值;否则为false 。否则,它将评估并返回其值。question ? answer1 : answer2
question
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运算符
的零-合并运算符()进行解包的可选,如果它包含一个值,或者返回一个默认值,如果是。表达式始终是可选类型。表达式必须匹配存储在里面的类型。a ?? b
a
b
a
nil
a
b
a
nil-coalescing运算符是以下代码的简写:
- a != nil ? a! : b
上面的代码使用三元条件运算符并强制展开(a!
)来访问nota
时包装在其中的值,否则返回。nil-coalescing运算符提供了一种更简洁的方法,以简洁易读的形式封装了此条件检查和展开。a
nil
b
笔记
如果的值为a
non- 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
变量定义为可选变量String
,默认值为nil
。因为userDefinedColorName
是可选类型,所以可以使用nil-coalescing运算符考虑其值。在上面的示例中,运算符用于确定String
名为的变量的初始值colorNameToUse
。因为userDefinedColorName
是nil
,所以表达式返回或的值。userDefinedColorName ?? defaultColorName
defaultColorName
"red"
如果您将非nil
值分配给userDefinedColorName
并再次执行nil-coalescing操作符检查,userDefinedColorName
则使用包装在其中的值代替默认值:
- userDefinedColorName = "green"
- colorNameToUse = userDefinedColorName ?? defaultColorName
- // userDefinedColorName isn't nil, so colorNameToUse is set to "green"
范围运算符
Swift包含多个range运算符,它们是表示一系列值的快捷方式。
近程运算符
的封闭范围操作符(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
欲了解更多有关for
-in
循环,看到控制流。
半开范围运算符
所述半开区间运算符(a..<b
)限定的范围内,从运行a
到b
,但不包括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
请注意,该数组包含四个项目,但0..<count
仅计入3
(数组中最后一个项目的索引),因为它是一个半开范围。有关数组的更多信息,请参见Arrays。
单面射程
封闭范围运算符具有在一个方向上尽可能连续的范围的另一种形式,例如,范围包括从索引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
逻辑运算符
逻辑运算符修改或组合布尔逻辑值true
和false
。Swift支持基于C语言的三种标准逻辑运算符:
- 逻辑非(
!a
) - 逻辑与()
a && b
- 逻辑或()
a || b
逻辑非运算符
的逻辑非运算符(!a
)反转一个布尔值,使得true
成为false
,和false
变true
。
逻辑NOT运算符是前缀运算符,并且紧接在其运算的值之前,没有任何空格。可以将其读取为“ not a
”,如以下示例所示:
- let allowedEntry = false
- if !allowedEntry {
- print("ACCESS DENIED")
- }
- // Prints "ACCESS DENIED"
该短语可以理解为“如果不允许输入”。仅在“不允许输入”为true时才执行下一行;也就是说,如果为。if !allowedEntry
allowedEntry
false
如本例所示,仔细选择布尔常量和变量名可以帮助保持代码的可读性和简洁性,同时避免出现双重否定或使逻辑语句混乱的情况。
逻辑与运算符
的逻辑AND运算符()创建逻辑表达式,其中这两个值必须为整体表达也有。a && b
true
true
如果任一值为false
,则整体表达式也将为false
。实际上,如果第一个值是false
,则第二个值甚至都不会被求值,因为它不可能使整个表达式等于true
。这称为短路评估。
本示例考虑两个Bool
值,并且仅当两个值均为时才允许访问true
:
- let enteredDoorCode = true
- let passedRetinaScan = false
- if enteredDoorCode && passedRetinaScan {
- print("Welcome!")
- } else {
- print("ACCESS DENIED")
- }
- // Prints "ACCESS DENIED"
逻辑或运算符
的逻辑OR运算符()是来自两个相邻管字符制成中缀运算符。您可以使用它来创建逻辑表达式,其中对于整个表达式而言,两个值中只有一个必须是。a || b
true
true
与上面的逻辑AND运算符类似,逻辑OR运算符使用短路评估来考虑其表达式。如果逻辑OR表达式的左侧为true
,则不会评估右侧,因为它无法更改整个表达式的结果。
在下面的示例中,第一个Bool
值(hasDoorKey
)为false
,但第二个值(knowsOverridePassword
)为true
。因为一个值是true
,所以整个表达式的计算结果也为true
,并且允许访问:
- 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!"
本示例使用Multiple&&
和||
运算符创建更长的复合表达式。但是,&&
and||
运算符仍然仅对两个值进行运算,因此实际上这是链接在一起的三个较小的表达式。该示例可以理解为:
如果我们输入了正确的门密码并通过了视网膜扫描,或者我们具有有效的门钥匙,或者如果我们知道紧急越权密码,则允许访问。
根据,和的值enteredDoorCode
,前两个子表达式为。但是,紧急越权密码是已知的,因此整体复合表达式的计算结果仍为。passedRetinaScan
hasDoorKey
false
true
笔记
Swift逻辑运算符&&
和||
是左关联的,这意味着具有多个逻辑运算符的复合表达式首先评估最左边的子表达式。
显式括号
有时在不需要括号时将其包含在内很有用,以使复杂表达式的意图更易于阅读。在上面的门访问示例中,在复合表达式的第一部分周围添加括号以使其意图明确是很有用的:
- if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
- print("Welcome!")
- } else {
- print("ACCESS DENIED")
- }
- // Prints "Welcome!"
括号清楚表明,前两个值被视为整体逻辑中单独可能状态的一部分。复合表达式的输出不会改变,但是总体目的对于读者来说更加清楚。可读性总是比简洁性更受青睐;在有助于您明确意图的地方加上括号。