
模式匹配中两个最关键的关键词:case 与 where,其中 where 语句可以用来设置约束条件、限制类型等。
在枚举中的应用
- 基本用法。原始值枚举成员的遍历
enum Direction {case Northcase Southcase Eastcase West}extension Direction: CustomStringConvertible {var description: String {switch self {case .North: return "↑"case .South: return "↓"case .East: return "→"case .West: return "←"}}}
- 1 由于一个 case 可以匹配多个条件,可以根据实际情况做出修改
extension Direction: CustomStringConvertible {var description: String {switch self {case .North, .South:return "vertical"case .West, .East:return "horizontal"}}}
- 再进一步。关联值枚举对象的匹配,若匹配成功则关联参数值会绑定到新创建的常量或变量上
enum Media {case Book(title: String, author: String, year: Int)case Movie(title: String, director: String, year: Int)case WebSite(url: URL, title: String)}extension Media {var mediaTitle: String {switch self {case .Book(title: let aTitle, author: _, year: _):return aTitlecase .Movie(title: let aTitle, director: _, year: _):return aTitlecase .WebSite(url: _, title: let aTitle):return aTitle}}}
- 1 以下两行代码等价
case .Book(title: let aTitle, author: _, year: _):case let .Book(title: aTitle, author: _, year: _):
- 2 关联参数值匹配固定值
extension Media {var isFromJulesVerne: Bool {switch self {case .Book(title: _, author: "Jules Verne", year: _): return truecase .Movie(title: _, director: "Jules Verne", year: _): return truedefault: return false}}}
extension Media {func checkAuthor(author: String) -> Bool {switch self {case .Book(title: _, author: author, year: _): return truecase .Movie(title: _, director: author, year: _): return truedefault: return false}}}
- 使用元组包含所有的关联参数
extension Media {var mediaTitle: String {switch self {case let .Book(tuple): return tuple.titlecase let .Movie(tuple): return tuple.titlecase let .WebSite(tuple): return tuple.title}}}
- 1 同样可以不用指定特定的元组来匹配任何关联值,所以下面四个表达式是等价的
case let .WebSite(tuple):case let .WebSite:case let .WebSite(_):case let .WebSite(_, _):
- 添加 where 子句
extension Media {var publishedAfter1930: Bool {switch self {case let .Book(_, _, year) where year > 1930: return truecase let .Movie(_, _, year) where year > 1930: return truecase .WebSite: return truedefault: return false}}}
在元组中的应用
在 Swift 当中,switch 并不像 ObjC 一样只能对整型或枚举进行匹配。可以使用 switch 对很多类型进行匹配,比如元组。这意味着我们只要将多个数据组合在一个元组中,就可以一次性匹配多个数据。此外要注意的是,switch 是按 case 模式被指定的顺序来判断求值的,并且它会在匹配到第一个满足的 case 后跳出。
let point = CGPoint(x: 7, y: 0)switch (point.x, point.y) {case (0, 0): print("On the origin!")case (0, _): print("x=0: on Y-axis!")case (_, 0): print("y=0: on X-axis!")case (let x, let y) where x == y: print("On y=x")default: print("Quite a random point here.")}
在字符中的应用
let letter: Character = "J"switch letter {case "A", "E", "I", "O", "U", "Y": print("Vowel")default: print("Consonant")}
在区间中的应用
let count = 7switch count {case Int.min..<0: print("Negative count, really?")case 0: print("Nothing")case 1: print("One")case 2..<5: print("A few")case 5..<10: print("Some")default: print("Many")}
func charType(car: Character) -> String {switch car {case "A", "E", "I", "O", "U", "Y", "a", "e", "i", "o", "u", "y":return "Vowel"case "A"..."Z", "a"..."z":return "Consonant"default:return "Other"}}
在类型判断中的应用
使用 as 和 is 匹配指定类型
protocol Medium {var title: String { get }}struct Book: Medium {let title: Stringlet author: Stringlet year: Int}struct Movie: Medium {let title: Stringlet director: Stringlet year: Int}struct WebSite: Medium {let url: NSURLlet title: String}
let media: [Medium] = [Book(title: "20,000 leagues under the sea", author: "Jules Vernes", year: 1870),Movie(title: "20,000 leagues under the sea", director: "Richard Fleischer", year: 1955)]for medium in media {print(medium.title)switch medium {case let b as Book:print("Book published in \(b.year)")case let m as Movie:print("Movie released in \(m.year)")case is WebSite: // equal to: let _ as WebSiteprint("A WebSite with no date")default:print("No year info for \(medium)")}}
在可选类型中的应用
let anOptional: Int? = 2switch anOptional {case 0: print("Zero") // or `case 0?:`case 1: print("One") // or `case 1?:`case 2: print("Two") // or `case 2?:`case nil: print("None")default: print("Other")}
简洁高效的匹配模式 *
if case、guard case、for case [let …] [where …] 都是对 switch-case 的简化,与特定 case 匹配。
比如 if case let x = y { … } 严格等同于 switch y { case let x: … }:当你只想与一条 case 匹配时,这种更紧凑的语法尤其有用。有多个 case 时更适合使用 switch。
另外 if 或 guard 后面如果接 where 子句,需将 where 关键字替换成逗号。
enum Media {case Book(title: String, author: String, year: Int)case Movie(title: String, director: String, year: Int)case WebSite(urlString: String)}let m = Media.Movie(title: "Captain America: Civil War", director: "Russo Brothers", year: 2016)if case let Media.Movie(title, _, _) = m {print("This is a movie named \(title)")}
enum NetworkResponse {case Response(URLResponse, NSData)case Error(NSError)}func processRequestResponse(response: NetworkResponse) {guard case let .Response(urlResp, data) = response,let httpResp = urlResp as? HTTPURLResponse, 200..<300 ~= httpResp.statusCode else {print("Invalid response, can't process")return}print("Processing \(data.length) bytes…")}
enum Media {case Book(title: String, author: String, year: Int)case Movie(title: String, director: String, year: Int)case WebSite(urlString: String)}let mediaList: [Media] = [.Book(title: "Harry Potter and the Philosopher's Stone", author: "J.K. Rowling", year: 1997),.Movie(title: "Harry Potter and the Philosopher's Stone", director: "Chris Columbus", year: 2001),.Book(title: "Harry Potter and the Chamber of Secrets", author: "J.K. Rowling", year: 1999),.Movie(title: "Harry Potter and the Chamber of Secrets", director: "Chris Columbus", year: 2002),]print("Movies only:")for case let Media.Movie(title, _, year) in mediaList {print(" - \(title) (\(year))")}
在循环遍历中的应用 where
let scores = [20, 8, 59, 60, 70, 80]scores.forEach {switch $0 {case let x where x >= 60:print("及格")default:print("不及格")}}
for value in 0..<5 where value > 2 {print(value)}
for (index, value) in (0..<5).enumerated() where index > 2 && value > 2 {print(index, value)}
在异常捕获中的应用 where
enum ExceptionError: Error {case httpCode(Int)}func throwError() throws {throw ExceptionError.httpCode(500)}do {try throwError()} catch ExceptionError.httpCode(let httpCode) where httpCode >= 500{print("server error")} catch {print("other error")}
在扩展中的应用 where
protocol SomeProtocol {}class ClassA: SomeProtocol {let param = 100}class ClassB {let param = 200}extension SomeProtocol where Self: ClassA {func showParam() {print("ClassA showParam: \(self.param)")}}extension SomeProtocol where Self: ClassB {func showParam() {print("ClassB showParam: \(self.param)")}}let a = ClassA()let b = ClassB()a.showParam()// b.showParam()
在泛型中的应用 where
protocol SomeProtocol {}func test<T: SomeProtocol>(value: T) {}func test<T>(value: T) where T: SomeProtocol {}
在协议中的应用 where
protocol Sequence {associatedtype Element where Self.Element == Self.Iterator.Element}
