2024-07-23 15:52:44
,某些文章具有时效性,若有错误或已失效,请在下方留言。Swift 的 switch
语句具有灵活却富有表现力的匹配模式。
基本使用
单值匹配
单值字符串匹配
let name = "twostraws"
switch name {
case "bilbo":
print("Hello, Bilbo Baggins!")
case "twostraws":
print("Hello, Paul Hudson!")
default:
print("Authentication failed")
}
多值匹配
多值匹配主要是通过元组实现匹配
let name = "twostraws"
let password = "fr0st1es"
switch (name, password) {
case ("bilbo", "bagg1n5"):
print("Hello, Bilbo Baggins!")
case ("twostraws", "fr0st1es"):
print("Hello, Paul Hudson!")
default:
print("Who are you?")
}
如果您愿意,可以将两个值合并为一个元组,然后进行匹配。
let authentication = (name: "twostraws", password: "fr0st1es")
switch authentication {
case ("bilbo", "bagg1n5"):
print("Hello, Bilbo Baggins!")
case ("twostraws", "fr0st1es"):
print("Hello, Paul Hudson!")
default:
print("Who are you?")
}
在这种情况下,元组的两个部分都必须与 case
相匹配才能执行。
部分匹配
在处理元组时,有时只需要部分匹配:只关心某些值,但不关心其他值。在这种情况下,使用下划线表示 "任何值都可以"。
let authentication = (name: "twostraws", password: "fr0st1es", ipAddress: "127.0.0.1")
switch authentication {
case ("bilbo", "bagg1n5", _):
print("Hello, Bilbo Baggins!")
case ("twostraws", "fr0st1es", _):
print("Hello, Paul Hudson!")
default:
print("Who are you?")
}
Swift会使用它找到的第一个匹配的case
,因此您需要确保首先查找最具体的内容。
如果你想匹配元组的一部分,但仍想知道其它部分是什么,可以使用 let
语法。
switch authentication {
case ("bilbo", "bagg1n5", _):
print("Hello, Bilbo Baggins!")
case ("twostraws", let password, _):
print("Hello, Paul Hudson“your password was \(password)!")
default:
print("Who are you?")
}
匹配计算元组
元组和其他数据结构一样,可以使用动态代码来创建。当你想将元组中的值范围缩小到一个较小的子集,从而只需要少量的 case 语句时,这一点尤其有用。
func fizzbuzz(number: Int) -> String {
switch (number % 3 == 0, number % 5 == 0) {
case (true, false):
return "Fizz"
case (false, true):
return "Buzz"
case (true, true):
return "FizzBuzz"
case (false, false):
return String(number)
}
}
print(fizzbuzz(number: 5)) // Buzz
循环
使用元组的一部分进行模式匹配非常简单:可以告诉 Swift
应该匹配什么,使用 let
将一个值绑定到一个局部常量,或者使用 _
来表示你并不关心某个值是什么。
在处理循环时,可以设置只有当项目符合我们指定条件时,菜对其循环。从一个基本例子开始:
let twostraws = (name: "twostraws", password: "fr0st1es")
let bilbo = (name: "bilbo", password: "bagg1n5")
let taylor = (name: "taylor", password: "fr0st1es")
let users = [twostraws, bilbo, taylor]
for user in users {
print(user.name)
}
这会创建一个元组数组,然后在每个元组上循环并打印其 name
值。
可以在元组中使用 case 来匹配元组中的特定值。
for case ("twostraws", "fr0st1es") in users {
print("User twostraws has the password fr0st1es")
}
使用相同的语法将本地常量绑定到每个元组的值上
for case (let name, let password) in users {
print("User \(name) has the password \(password)")
}
通常情况下,最好还是将 let 重新排列成这样:
for case let (name, password) in users {
print("User \(name) has the password \(password)")
}
将这两种方法结合在一起
for case let (name, "fr0st1es") in users {
print("User \(name) has the password \"fr0st1es\"")
}
这将过滤 users
数组,以便循环中只使用密码为 "fr0st1es "的项目。
匹配可选值
.some 和 .none
使用 .some
和 .none
来匹配 "有值 "和 "无值"。
let name: String? = "twostraws"
let password: String? = "fr0st1es"
switch (name, password) {
case let(.some(matchedName), .some(matchedPassword)):
print("Hello, \(matchedName)")
case let(.some(matchedName), .none):
print("Please enter a password.")
default:
print("Who are you?")
}
?和 nil
使用 ?
进行可选值的匹配,问号的作用与可选链的作用类似:只有找到值才继续。
let name: String? = "twostraws"
let password: String? = "fr0st1es"
switch (name, password) {
case let(name?, password?):
print("Hello, \(name)")
case let(username?, nil):
print("Please enter a password.")
default:
print("Who are you?")
}
这两种方法在 for case let 代码中同样有效。
import Foundation
let data: [Any?] = ["Bill", nil, 69, "Ted"]
for case let .some(datum) in data {
print(datum)
}
for case let datum? in data {
print(datum)
}
匹配范围
条件语句
使用模式匹配运算符 ~=
进行范围匹配。
let age = 36
if 0..<18 ~= age {
print("You have the energy and time, but not the money")
} else if 18 ..< 70 ~= age {
print("You have the energy and money, but not the time")
} else {
print("You have the time and money, but not the energy")
}
0 ..< 18
会创建一个 Range
结构的实例,而 Range
结构有自己的方法集,它的 contains()
方法特别有用。
let age = 36
if (0..<18).contains(age) {
print("You have the energy and time, but not the money")
} else if (18 ..< 70).contains(age) {
print("You have the energy and money, but not the time")
} else {
print("You have the time and money, but not the energy")
}
可以将这种范围匹配与现有的元组匹配代码结合起来
let user = (name: "twostraws", password: "fr0st1es", age: 36)
switch user {
case let (name, _, 0 ..< 18):
print("\(name) has the energy and time, but no money")
case let (name, _, 18 ..< 70):
print("\(name) has the money and energy, but no time")
case let (name, _, _):
print("\(name) has the time and money, but no energy")
}
匹配枚举和关联值
基本枚举匹配
enum WeatherType {
case cloudy
case sunny
case windy
}
let today = WeatherType.cloudy
switch today {
case .cloudy:
print("It's cloudy")
case .sunny:
print("It's windy")
case .windy:
print("It's sunny")
}
枚举关联值匹配
忽略关联值
enum WeatherType {
case cloudy(coverage: Int)
case sunny
case windy
}
let today = WeatherType.cloudy(coverage: 100)
switch today {
case .cloudy:
print("It's cloudy")
case .sunny:
print("It's windy")
case .windy:
print("It's sunny")
}
使用这种方法,实际的 switch
代码将保持不变。
使用关联值
enum WeatherType {
case cloudy(coverage: Int)
case sunny
case windy
}
let today = WeatherType.cloudy(coverage: 100)
switch today {
case .cloudy(let coverage):
print("It's cloudy with \(coverage)% coverage")
case .sunny:
print("It's windy")
case .windy:
print("It's sunny")
}
关联值与范围匹配
enum WeatherType {
case cloudy(coverage: Int)
case sunny
case windy
}
let today = WeatherType.cloudy(coverage: 100)
switch today {
case .cloudy(let coverage) where coverage == 0:
print("You must live in Death Valley")
case .cloudy(let coverage) where (1...50).contains(coverage):
print("It's a bit cloudy, with \(coverage)% coverage")
case .cloudy(let coverage) where (51...99).contains(coverage):
print("It's very cloudy, with \(coverage)% coverage")
case .cloudy(let coverage) where coverage == 0:
print("You must live in the UK")
case .windy:
print("It's sunny")
default:
print("it's sunny")
}
如果要在循环中匹配关联值,可以使用 case let
关键字。
let forecast: [WeatherType] = [.cloudy(coverage: 40), .sunny, .windy, .cloudy(coverage: 100), .sunny]
for case let .cloudy(coverage) in forecast {
print("It's cloudy with \(coverage)% coverage")
}
使用 where 关键字
可以使用 where
删除可选项
let celebrities: [String?] = ["Michael Jackson", nil, "Michael Caine", nil, "Michael Jordan"]
for name in celebrities where name != nil {
print(name)
}
这当然可行,但它对循环中字符串的可选性没有做任何处理,因此会打印出这样的结果:
Optional("Michael Jackson")
Optional("Michael Caine")
Optional("Michael Jordan")
相反,应使用 for case let
来处理可选性,并使用 where 来关注过滤值。
for case let name? in celebrities {
print(name)
}
运行时, name 将只包含有值的字符串,因此其输出将是
Michael Jackson
Michael Caine
Michael Jordan
《pro swift》
暂无评论内容