莎士比亚曾经说过:“To be or not to be, that is the question.“
这正好也是编程的逻辑中心问题:评估一个条件是真还是假。
今天我们一起来探讨学习Swift语言中的条件语句。
如何检查一个条件的真或假?
程序经常会做出选择:
- 如果学生的考试成绩超过 80 分,则打印成功信息。
- 如果用户输入的名字按字母顺序排列在朋友的名字之后,则将朋友的名字放在前面。
- 如果在数组中添加数字后,数组中包含的条目超过 3 个,则删除最老的条目。
- 如果用户被要求输入自己的名字,但却什么也没输入,那么就给他们一个 “匿名 “的默认名字。
Swift 使用 if
语句来处理这些问题,它允许我们检查一个条件,并在条件为真时运行一些代码。它们看起来像这样:
if someCondition {
print("Do something")
}
让我们来分析一下:
- 条件以
if
开头,向 Swift 表示我们要在代码中检查某种条件。 someCondition
部分是写入条件的地方——分数是否超过 80 分?数组是否包含 3 个以上的项目?这都是条件。- 如果条件为真,即分数真的超过了 80 分,那么我们就打印 “
Do something
“信息。
当然,这并不是代码的全部: 我还没提到 {
和 }
符号。这些符号被称为大括号——更确切地说,是开大括号和闭大括号。
这些大括号在 Swift 中被广泛用于标记代码块:开头的大括号开始代码块,结尾的大括号结束代码块。在代码块中,如果我们的条件在检查时恰好为真,我们要运行的代码就会在代码块中出现,在我们的例子中就是打印一条消息。
你可以根据需要在代码块中加入尽可能多的代码:
if someCondition {
print("Do something")
print("Do something else")
print("Do a third thing")
}
当然,真正重要的是 someCondition
部分,因为这才是你的检查代码:你到底想检查什么条件?
让我们以分数为例:如果分数常量超过 80,我们就打印一条信息。代码如下:
let score = 85
if score > 80 {
print("Great job!")
}
在这段代码中,score > 80
是我们的条件。你应该还记得学校里 >
的意思是 “大于”,所以我们的完整条件是 “如果分数大于 80″。如果大于 80,就会打印出 “Great job!”。
这个 >
符号是一个比较运算符,因为它比较两个事物并返回布尔结果:左边的事物是否大于右边的事物?你还可以用 <
表示小于,用 >=
表示 “大于或等于”,用 <=
表示 “小于或等于”。
让我们试一试——你认为以下这段代码会打印出什么结果?
let speed = 88
let percentage = 85
let age = 18
if speed >= 88 {
print("Where we're going we don't need roads.")
}
if percentage < 85 {
print("Sorry, you failed the test.")
}
if age >= 18 {
print("You're an adult.")
}
试着在头脑中运行代码——哪些 print()
行将会被实际运行?
那么,如果速度大于或等于 88,我们的第一行就会运行,因为它正好是 88,所以第一行 print()
代码就会运行。
第二行将在百分比小于 85 时运行,因为正好是 85,所以第二行 print()
不会运行——我们用的是小于,而不是小于或等于。
第三个将在年龄大于或等于 18 时运行,由于正好是 18,第三个 print()
将运行。
现在让我们试试第二个示例条件:如果用户输入的名字按字母顺序排列在其朋友名字的后面,则将朋友的名字放在前面。我们已经看到 <
、>=
和其他函数在处理数字时的出色表现,但它们在处理字符串时也同样出色:
let ourName = "Dave Lister"
let friendName = "Arnold Rimmer"
if ourName < friendName {
print("It's \(ourName) vs \(friendName)")
}
if ourName > friendName {
print("It's \(friendName) vs \(ourName)")
}
因此,如果按字母顺序排列时,ourName
中的字符串在 friendName
中的字符串之前,就会按照我们的要求先打印 ourName
,然后再打印 friendName
。
让我们来看看第三个示例条件:如果向数组中添加一个数字使其包含的条目超过 3 个,则删除最老的条目。我们已经遇到过 append()
、count
和 remove(at:)
,所以现在我们可以把这三个条件组合在一起,像这样:
// Make an array of 3 numbers
var numbers = [1, 2, 3]
// Add a 4th
numbers.append(4)
// If we have over 3 items
if numbers.count > 3 {
// Remove the oldest number
numbers.remove(at: 0)
}
// Display the result
print(numbers)
现在让我们看看第四个示例条件:如果用户被要求输入姓名,但却什么也没输入,那么就给他们一个默认的 “匿名”姓名。
要解决这个问题,你首先需要认识另外两个你会经常用到的比较运算符,这两个运算符都是处理相等关系的。第一个是 ==
,意思是 “等于”,使用方法如下:
let country = "Canada"
if country == "Australia" {
print("YES")
}
第二个是 !=
,意思是 “不等于”,用法如下:
let name = "Taylor Swift"
if name != "Anonymous" {
print("Welcome, \(name)")
}
在我们的例子中,我们要检查用户输入的用户名是否为空,我们可以这样做:
// Create the username variable
var username = "taylorswift13"
// If `username` contains an empty string
if username == "" {
// Make it equal to "Anonymous"
username = "Anonymous"
}
// Now print a welcome message
print("Welcome, \(username)!")
该**""
**是一个空字符串:我们从引号开始,到引号结束,中间没有任何内容。通过将用户名与之比较,我们可以检查用户是否也输入了空字符串作为用户名,这正是我们想要的。
现在,还有其他方法可以进行这种检查,重要的是要了解它们的作用。
首先,我们可以将字符串的计数(有多少个字母)与 0 进行比较,就像这样:
if username.count == 0 {
username = "Anonymous"
}
在任何语言中,将一个字符串与另一个字符串进行比较都不会很快,因此我们用整数比较取代了字符串比较:字符串中的字母数是否等于 0?
在许多语言中这都非常快,但在 Swift 中却不是。要知道,Swift 支持各种复杂的字符串——几乎所有人类语言都可以使用,包括表情符号,而其他许多编程语言却无法做到这一点。不过,这种强大的支持也是有代价的,其中一个代价就是,如果要询问字符串的长度,Swift 就必须一个一个地数清所有字母,而不是将长度与字符串分开存储。
所以,想想看,如果你有一个庞大的字符串,其中存储了莎士比亚的全部作品。我们对 count == 0
的小检查必须遍历并计算字符串中的所有字母,尽管只要我们计算了至少一个字符,我们就知道了问题的答案。
因此,Swift 为其所有字符串、数组、字典和集合添加了第二个功能:isEmpty
。如果你正在检查的东西里面什么都没有,它就会返回 true
,我们可以用它来修复我们的条件,就像这样:
if username.isEmpty == true {
username = "Anonymous"
}
这样更好,但我们还可以更进一步。要知道,最终最重要的是你的条件必须归结为 “true
“或 “false
“;Swift 不允许任何其他条件。在我们的例子中,username.isEmpty
已经是一个布尔值,这意味着它要么为真要么为假,所以我们可以让代码变得更简单:
if username.isEmpty {
username = "Anonymous"
}
如果 isEmpty
为真,则条件通过,用户名被设置为匿名,否则条件失败。
Swift 如何让我们比较多种类型的数据?
Swift 可以让我们直接比较多种值,这意味着我们可以检查各种值是否相等并进行比较。例如,如果我们有如下值:
let firstName = "Paul"
let secondName = "Sophie"
let firstAge = 40
let secondAge = 10
然后,我们可以通过各种方式对它们进行比较:
print(firstName == secondName)
print(firstName != secondName)
print(firstName < secondName)
print(firstName >= secondName)
print(firstAge == secondAge)
print(firstAge != secondAge)
print(firstAge < secondAge)
print(firstAge >= secondAge)
在幕后,Swift 以一种非常巧妙的方式实现了这一点,它实际上可以比较各种各样的事物。例如,Swift 有一种用于存储日期的特殊类型,叫做 Date
,你可以使用相同的运算符来比较日期:例如:someDate < someOtherDate
。
我们甚至可以要求 Swift 使我们的枚举具有可比性,就像下面这样:
enum Sizes: Comparable {
case small
case medium
case large
}
let first = Sizes.small
let second = Sizes.large
print(first < second)
这将打印 “true
“,因为在这个枚举列表中,small
排在 large
之前。
如何检查多个条件
当我们使用 if
时,我们必须提供 Swift 的某种条件,该条件在评估后要么为真,要么为假。如果要检查多个不同的值,可以像这样把它们一个接一个地放在一起:
let age = 16
if age >= 18 {
print("You can vote in the next election.")
}
if age < 18 {
print("Sorry, you're too young to vote.")
}
但仔细想想,这样做并不高效:我们的两个条件是相互排斥的,因为如果某人大于或等于 18(第一个条件),那么他就不可能小于 18(第二个条件),反之亦然。我们让 Swift 做了不需要做的工作。
在这种情况下,Swift 为我们提供了一种更高级的条件,让我们可以在代码中添加 else
块,即在条件不为真时运行一些代码。
使用 else
,我们可以将之前的代码重写成这样:
let age = 16
if age >= 18 {
print("You can vote in the next election.")
} else {
print("Sorry, you're too young to vote.")
}
现在 Swift 只需检查一次年龄:如果大于或等于 18 岁,则运行第一段 print()
代码,但如果小于 18 岁,则运行第二段 print()
代码。
因此,现在我们的条件是这样的:
if someCondition {
print("This will run if the condition is true")
} else {
print("This will run if the condition is false")
}
还有一种更高级的条件叫 else if
,它可以让你在第一项检查失败后运行新的检查。你可以根据需要只使用一个 else if
,也可以使用多个 else if
,甚至可以根据需要将 else if
与 else
结合使用。但是,else
只能有一个,因为这意味着 “如果所有其他条件都为假”。
下面就是这种情况:
let a = false
let b = true
if a {
print("Code to run if a is true")
} else if b {
print("Code to run if a is false but b is true")
} else {
print("Code to run if both a and b are false")
}
如果需要,您可以不断添加更多的 else if
条件,但要注意代码不要太复杂!
除了使用 else
和 else if
来创建更高级的条件外,您还可以检查多件事情。例如,我们可能想说 “如果今天的温度超过 20 摄氏度但低于 30 摄氏度,则打印一条信息”。
这有两个条件,所以我们可以这样写:
let temp = 25
if temp > 20 {
if temp < 30 {
print("It's a nice day.")
}
}
虽然这样做效果很好,但 Swift 提供了一个更简短的替代方法:我们可以使用 &&
将两个条件组合在一起,只有当条件中的两个部分为真时,整个条件才会为真。
因此,我们可以把代码改成这样:
if temp > 20 && temp < 30 {
print("It's a nice day.")
}
你应该把 &&
读作 “并且”,这样我们的整个条件就变成了 “如果温度大于 20 并且小于 30,则打印一条信息”。之所以称其为逻辑运算符,是因为它能将布尔值组合成一个新的布尔值。
与**&&
** 的对应的运算符是两个竖线 ||
,意思是 “或”。&&
只有在两个子条件都为真的情况下才会使条件为真,而 ||
则是在任何一个子条件都为真的情况下就会使条件为真。
例如,我们可以说,如果用户年满 18 周岁,就可以购买游戏;如果用户未满 18 周岁,则必须得到父母的许可。我们可以使用 ||
这样写:
let userAge = 14
let hasParentalConsent = true
if userAge >= 18 || hasParentalConsent == true {
print("You can buy the game")
}
这将打印出 “You can buy the game”,因为尽管我们条件的前半部分失败了,即用户未满 18 周岁,但后半部分通过了,因为他们确实获得了父母的同意。
请记住,可以去掉条件中的 == true
,因为我们显然已经在检查布尔值了。因此,我们可以这样写:
if userAge >= 18 || hasParentalConsent {
print("You can buy the game")
}
最后,让我们来尝试一个更复杂的示例,它同时结合了 if
、else if
、else
和 ||
等条件,甚至还展示了枚举如何与条件相结合。
在这个示例中,我们将创建一个名为 TransportOption
的枚举,它包含五种情况:飞机、直升机、自行车、汽车和滑板车。然后,我们将把一个示例值赋值给一个常量,并进行一些检查:
- 如果我们要乘飞机或直升机去某个地方,将打印 “Let’s fly!”
- 如果我们要骑自行车,将打印 “I hope there’s a bike path…”
- 如果我们开车,将打印 “Time to get stck in traffic.”。
- 否则,会打印 “I’m going to hire a scooter now!”
代码如下:
enum TransportOption {
case airplane, helicopter, bicycle, car, scooter
}
let transport = TransportOption.airplane
if transport == .airplane || transport == .helicopter {
print("Let's fly!")
} else if transport == .bicycle {
print("I hope there's a bike path…")
} else if transport == .car {
print("Time to get stuck in traffic.")
} else {
print("I'm going to hire a scooter now!")
}
我想说明一下代码中的几个部分:
- 当我们设置
transport
的值时,我们需要明确指出我们指的是TransportOption.airplane
。我们不能只写.airplane
,因为 Swift 不明白我们指的是TransportOption
枚举。 - 一旦我们第一次写过了**
TransportOption.airplane
**,我们就不需要再写TransportOption
了,因为 Swift 知道transport
必须是某种TransportOption
。因此,我们可以检查它是否等于.airplane
而不是TransportOption.airplane
。 - 代码使用
||
来检查transport
是否等于.airplane
或等于.helicopter
,如果两者之一为真,则条件为真,并打印 “Let’s fly!”。 - 如果第一个条件失败,即运输模式不是**
.airplane
或.helicopter
,则运行第二个条件:运输模式是.bicycle
**吗?如果是,则打印 “I hope there’s a bike path…”。 - 如果我们也不骑自行车,那么我们就检查我们是否开车。如果是,则打印 “Time to get stuck in traffic.”。
- 最后,如果前面的条件都不成立,则运行
else
代码块,这意味着我们要骑摩托车。
if 和 else if 有什么区别?
刚开始学习 Swift 时,可能很难知道什么时候该使用 else,什么时候该使用 else if,以及它们之间的区别到底是什么。
好吧,让我们从一个示例开始:
let score = 9001
我们可以这样写一个简单的条件来检查分数是否超过 9000:
if score > 9000 {
print("It's over 9000!")
}
现在,如果我们想为等于或低于 9000 的分数打印不同的信息,我们可以这样写:
if score > 9000 {
print("It's over 9000!")
}
if score <= 9000 {
print("It's not over 9000!")
}
这完全没问题,你的代码也会完全按照您的预期运行。但现在我们给 Swift 增加了工作:它需要两次检查 score
的值。对于一个简单的整数,这样做的速度非常快,但如果我们的数据更复杂,速度就会更慢。
这就是 else
的作用所在,因为它意味着 “如果我们检查的条件不为真,则运行这段代码”。
因此,我们可以将之前的代码重写成这样:
if score > 9000 {
print("It's over 9000!")
} else {
print("It's not over 9000!")
}
有了这一改动,Swift 只需检查一次分数,而且我们的代码更简短、更易读。
现在想象一下,我们需要三条消息:分数超过 9000 时一条,正好 9000 时一条,低于 9000 时一条。我们可以这样写:
if score > 9000 {
print("It's over 9000!")
} else {
if score == 9000 {
print("It's exactly 9000!")
} else {
print("It's not over 9000!")
}
}
同样,这样做也没有问题,就像你希望的那样。不过,我们可以通过使用 else if
来使代码更易于阅读,它可以让我们将 else
与后面的 if
直接结合起来,就像这样:
if score > 9000 {
print("It's over 9000!")
} else if score == 9000 {
print("It's exactly 9000!")
} else {
print("It's not over 9000!")
}
为了尝试这个方法,我想使用一个 Swift 函数 print()
:在运行该函数时输入一些文本,然后将其打印出来。
这让我们的代码更容易阅读和理解,因为我们不再需要嵌套的条件,而是有一个可以向下阅读的流程。
你可以有任意多的 else if
检查,但你需要的是一个 if
和零个或一个 else
。
如何检查多个条件
Swift 为我们提供了 &&
和 ||
来同时检查多个条件,当只使用两个条件时,它们就非常简单了。
举个例子,假设我们在运行一个论坛,用户可以在论坛上发布消息,也可以删除他们拥有的任何消息。我们可以这样编写代码:
if isOwner == true || isAdmin == true {
print("You can delete this post")
}
当我们要检查几件事时,情况就会变得混乱。例如,我们可以说普通用户只有在我们允许的情况下才能删除消息,但管理员却可以随时删除帖子。我们可以这样编写代码:
if isOwner == true && isEditingEnabled || isAdmin == true {
print("You can delete this post")
}
但这是要检查什么呢?&&
和 ||
检查的执行顺序是什么?可能是这个意思:
if (isOwner == true && isEditingEnabled) || isAdmin == true {
print("You can delete this post")
}
这句话的意思是 “如果是所有者,并且编辑功能已启用,你可以删除帖子;如果你是管理员,即使您不是帖子的所有者,您也可以删除帖子”。这很有道理:如果允许编辑,用户可以删除自己的帖子,但管理员总是可以删除帖子。
不过,你也可以这样理解:
if isOwner == true && (isEditingEnabled || isAdmin == true) {
print("You can delete this post")
}
现在,它的意思完全不同了:”启用了编辑功能或者你是管理员这两个条件任意一个成立,并且你是贴子的所有者,那么你才可以删除帖子”。这意味着管理员不能删除他们不拥有的帖子,这就说不通了。
显然,Swift 不喜欢这种模棱两可的说法,所以它总是按照我们这样写来解释代码:
if (isOwner == true && isEditingEnabled) || isAdmin == true {
print("You can delete this post")
}
不过,老实说,让 Swift 来解决这个问题并不是一种好的体验,所以我们可以自己插入括号来明确我们的意思。
在这方面没有具体的建议,但实际上,只要在一个条件中混合使用 &&
和 ||
,就几乎肯定要使用括号来明确结果。
如何使用switch语句检查多个条件
你可以反复使用 if
和 else if
来检查各种条件,但这样读起来会有点费劲。例如,如果我们有一个来自枚举的天气预报,我们可以根据一系列条件选择要打印的信息,就像这样:
enum Weather {
case sun, rain, wind, snow, unknown
}
let forecast = Weather.sun
if forecast == .sun {
print("It should be a nice day.")
} else if forecast == .rain {
print("Pack an umbrella.")
} else if forecast == .wind {
print("Wear something warm")
} else if forecast == .snow {
print("School is cancelled.")
} else {
print("Our forecast generator is broken!")
}
这个方法可行,但也有问题:
- 尽管我们每次检查的都是同一件事,但我们还是不得不写**
forecast
**。 - 我不小心检查了两次
.rain
,尽管第二次检查永远不会为真,因为只有在第一次检查失败时才会执行第二次检查。 - 我根本没有检查
.snow
,所以我们丢失了功能。
我们可以使用一种名为 switch 的不同条件检查方法来解决上述三个问题。这同样可以让我们逐个检查单个情况,但现在 Swift 可以提供帮助。在枚举的情况下,Swift 知道枚举可能有的所有情况,因此如果我们漏掉一个或检查了两次,Swift 就会报错。
因此,我们可以用以下方法替换所有 if
和 else if
检查:
switch forecast {
case .sun:
print("It should be a nice day.")
case .rain:
print("Pack an umbrella.")
case .wind:
print("Wear something warm")
case .snow:
print("School is cancelled.")
case .unknown:
print("Our forecast generator is broken!")
}
让我们来分析一下:
- 我们以
switch forecast
开始,它告诉 Swift 这是我们要检查的值。 - 然后,我们有一串
case
语句,每个case
都是我们要与forecast
进行比较的值。 - 我们的每个
case
都列出了一种天气类型,因为我们是根据 forecast 切换的,所以不需要写Weather.sun
、Weather.rain
等,Swift 知道这一定是某种天气类型。 - 在每种情况后,我们都会写一个冒号,以标记如果该情况匹配,则要运行的代码的起始位置。
- 我们使用收尾括号来结束
switch
语句。
如果你尝试将 .snow
改为 .rain
,你会发现 Swift 会出现两次警告:一次是我们检查了两次 .rain,另一次是我们的 switch 语句并不详尽——它没有处理所有可能的情况。
如果你用过其他编程语言,你可能会注意到 Swift 的 switch 语句有两处不同:
- 所有 switch 语句都必须是穷举性的,这意味着必须处理所有可能的值,因此不能意外遗漏。
- Swift 会执行与你要检查的条件相匹配的第一个
case
,但不会再执行更多。其他语言通常会继续执行所有后续情况下的其他代码,这通常是完全错误的默认做法。
尽管这两种做法都是对的,但 Swift 还是在需要时为我们提供了更多的控制。
首先,所有**switch
**语句都必须详尽无遗:必须确保涵盖所有可能的值。如果要在字符串上进行切换,那么显然不可能对所有可能的字符串进行穷举检查,因为字符串的数量是无限的,因此我们需要提供一个默认情况——在其他情况都不匹配时运行代码。
例如,我们可以切换包含地名的字符串:
let place = "Metropolis"
switch place {
case "Gotham":
print("You're Batman!")
case "Mega-City One":
print("You're Judge Dredd!")
case "Wakanda":
print("You're Black Panther!")
default:
print("Who are you?")
}
末尾的 default:
是默认情况,如果所有情况都不匹配,则运行默认情况。
请记住 Swift 会按顺序检查用例,并运行第一个匹配的用例。如果将 default
放在任何其他情况之前,该情况将毫无用处,因为它永远不会匹配,Swift 将拒绝构建您的代码。
其次,如果你明确希望 Swift 继续执行后续情况,请使用 fallthrough
。这种方法并不常用,但有时(只是有时)可以帮助您避免重复工作。
例如,有一首著名的圣诞歌曲叫《圣诞十二日》,随着歌曲的进行,一个不幸的人身上堆满了越来越多的礼物,到了第六天,他的家里已经堆满了礼物。
我们可以用 fallthrough
简单地模拟这首歌。首先,下面是不使用 fallthrough
时的代码:
let day = 5
print("My true love gave to me…")
switch day {
case 5:
print("5 golden rings")
case 4:
print("4 calling birds")
case 3:
print("3 French hens")
case 2:
print("2 turtle doves")
default:
print("A partridge in a pear tree")
}
这将打印出 “5 golden rings”,但这并不完全正确。第 1 天应该只打印 “A partridge in pear tree”,第 2 天应该先打印 “2 turtle doves”,然后再打印 “A partridge in a pear tree”,第 3 天应该打印 “3 French hens”、”2 turtle doves”,然后……你就明白了。
我们可以使用 fallthrough
来实现这种行为:
let day = 5
print("My true love gave to me…")
switch day {
case 5:
print("5 golden rings")
fallthrough
case 4:
print("4 calling birds")
fallthrough
case 3:
print("3 French hens")
fallthrough
case 2:
print("2 turtle doves")
fallthrough
default:
print("A partridge in a pear tree")
}
这将与第一种情况相匹配,并打印出 “5 golden rings”,但穿透行意味着第四种情况将执行并打印出 “4 calling birds”,这反过来又使用了穿透,从而打印出 “3 French hens”,依此类推。虽然与歌曲不完全匹配,但至少可以看到功能的运行!
什么时候应该使用 switch 语句而不是 if?
Swift 开发人员可以同时使用 switch 和 if 来检查代码中的多个值,而且通常并不存在选择其中一种而非另一种的硬性理由。尽管如此,有三个原因可以让你考虑使用 switch 而不是 if:
- Swift 要求其
switch
语句是穷举性的,这意味着你必须为每个可能的检查值(例如枚举的所有情况)设置一个case
块,或者你必须设置一个默认情况。而if
和else if
则不是这样,因此您可能会不小心漏掉一个case
。 - 使用
switch
检查一个值是否有多个可能的结果时,该值只会被读取一次,而使用if
则会被读取多次。当你开始使用函数调用时,这一点变得更加重要,因为其中有些函数调用可能会很慢。 - Swift 的
switch
的case
允许进行高级模式匹配,而if
则不方便。
还有一种情况,但比较模糊:一般来说,如果你想在三种或三种以上的可能状态下检查同一个值,你会发现人们更喜欢使用 switch
,而不是 if
,因为这样更容易辨认——我们在重复检查同一个值,而不是编写不同的条件。
PS:我之所以介绍 fallthrough
关键字,是因为它对来自其他编程语言的人来说很重要,但在 Swift 中使用它的情况却相当少见——如果你很难想出它在什么情况下可能有用,也不用担心,因为老实说,大多数情况下它都没有用!
如何使用三元条件运算符进行快速检查
在 Swift 中还有最后一种检查条件的方法,当你看到它时,很可能会想知道它什么时候有用。公平地说,在很长一段时间里,我很少使用这种方法,但正如你稍后会看到的,它在 SwiftUI 中真的很重要。
这种方法叫做三元条件运算符。要理解它为什么叫三元条件运算符,首先要知道 +、-、== 等运算符都被称为二元运算符,因为它们处理的是两部分输入:例如,2 + 5 处理的是 2 和 5。
三元运算符可以处理三个输入值,事实上,因为三元条件运算符是 Swift 中唯一的三元运算符,所以你经常会听到有人称它为 “三元运算符”。
不管怎么说,别再提它的名字了:它到底有什么作用呢?三元运算符允许我们检查一个条件,并返回两个值中的一个:条件为真时返回某值,条件为假时返回另一个值。
例如,我们可以创建一个名为 age
的常量来存储某人的年龄,然后再创建一个名为 canVote
的常量来存储此人是否可以投票:
let age = 18
let canVote = age >= 18 ? "Yes" : "No"
代码运行时,canVote
将被设置为 “Yes”,因为年龄被设置为 18 岁。
正如你所看到的,三元运算符分为三个部分:检查(age >= 18)、条件为真时(”Yes”)和条件为假时(”No”)。这使得它与普通的 if
和 else
块完全相同,顺序也一样。
- 我们的条件是什么?是年龄大于等于 18 岁。
- 条件为真时怎么办?返回 “Yes”,这样就可以存储在
canVote
中。 - 如果条件为假呢?返回 “No”。
我们再来看看其他例子,首先是一个简单的例子,它以 24 小时格式读取一个小时,并打印出两条信息中的一条:
let hour = 23
print(hour < 12 ? "It's before noon" : "It's after noon")
请注意,这个程序并没有将结果赋值给任何地方,而是根据 hour
的值打印出 true
或 false
的情况。
这里还有一个读取数组 count
作为条件的例子,然后返回两个字符串中的一个:
let names = ["Jayne", "Kaylee", "Mal"]
let crewCount = names.isEmpty ? "No one" : "\(names.count) people"
print(crewCount)
当你的条件使用 ==
来检查是否相等时,读起来就有点困难了,如图所示:
enum Theme {
case light, dark
}
let theme = Theme.dark
let background = theme == .dark ? "black" : "white"
print(background)
= theme ==
部分通常是人们难以读懂的部分,但要记住将其分解:
- 条件判断是:
theme == .dark
- 真:
“black”
- 假:
“white”
因此,如果 theme
等于 .dark
,则返回 “black”,否则返回 “white”,然后将其赋值给 background
。
现在,你可能想知道三元运算符为什么有用,尤其是当我们有常规的 if/else
条件时。我知道这不是一个很好的答案:有些时候,尤其是在 SwiftUI 中,我们别无选择,必须使用三元运算符。
通过我们检查小时数的代码,你可以大致看出问题所在:
let hour = 23
print(hour < 12 ? "It's before noon" : "It's after noon")
如果我们想使用 if
和 else
来写出这些代码,我们就需要写出这样的代码:
print(
if hour < 12 {
"It's before noon"
} else {
"It's after noon"
}
)
或者像这样运行两次 print()
:
if hour < 12 {
print("It's before noon")
} else {
print("It's after noon")
}
第二段代码在Swift可以正常工作,但在 SwiftUI 中几乎不可能,稍后你将看到这一点。所以,尽管你可能会想知道既然有了if
和else
为什么还要使用三元运算符,但请相信我:对于SwiftUI它很重要!
什么时候应该在 Swift 中使用三元运算符?
三元运算符可以让我们根据条件从两个结果中选择一个,而且非常简洁:
let isAuthenticated = true
print(isAuthenticated ? "Welcome!" : "Who are you?")
有些人非常依赖三元运算符,因为它能让代码变得非常简短;而有些人则尽量避免使用三元运算符,因为它会让代码变得更难读。
我非常赞同 “尽可能避免 “的观点,因为尽管这段代码较长,但我确实觉得它更容易理解:
if isAuthenticated {
print("Welcome")
} else {
print("Who are you?")
}
现在,三元运算符在 SwiftUI 中得到了广泛应用。我不想在这里给出代码示例,因为这可能会让人有点不知所措,但如果你愿意,你真的可以在这里使用三元运算符。即便如此,为了让代码更容易阅读,我还是会尽可能去掉三元运算符,但你应该亲自尝试一下,然后得出自己的结论。