你在代碼中使用if case了嗎?

模式匹配是swift語言的亮點(diǎn),如果運(yùn)用得當(dāng),能有效提升代碼的 逼格。比方說if case,guard case,for case。如過你還沒有使用過它們,或者不確信它們是否可行,不妨試試下面的內(nèi)容。

if case

case let x = y 表達(dá)式可以完成檢查 y 是否匹配模式 x。

表達(dá)式 if case let x = y { … } 則等同于表達(dá)式 switch y { case let x: … } 。前者是后者的一種簡寫,switch適用于多分支的模式匹配,而if case則適合于單條case的匹配情況。
比方說我們有這樣一個(gè)枚舉:

enum Media {
  case Book(title: String, author: String, year: Int)
  case Movie(title: String, director: String, year: Int)
  case WebSite(urlString: String)
}

如果使用switch進(jìn)行匹配的話:

let m = Media.Movie(title: "Captain America: Civil War", director: "Russo Brothers", year: 2016)

switch m {
  case let Media.Movie(title, _, _):
    print("This is a movie named \(title)")
  default: () 
}

我們只用到了單分支匹配,但需要描述 switch,default,啰嗦不?所以要:變

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)")
}

這樣寫有沒有感覺就像理了頭發(fā),清爽了許多,心情瞬間美好起來?其實(shí)不只是模式匹配,完全可以在混合一下條件表達(dá)式:

  if case let Media.Movie(_, _, year) = m where year < 1888 {
    print("Something seems wrong: the movie's year is before the first movie ever made.")
  }

通過if case表達(dá)式,我們幾乎把switch的所有本事都搬來了,愉快。

guard case

從模式匹配的角度來看,guard case與if case的語法結(jié)構(gòu)是完全相同的,它們的區(qū)別僅僅體現(xiàn)在guard關(guān)鍵字與if關(guān)鍵字的區(qū)別上。直接看一個(gè)例子。

enum NetworkResponse {
  case Response(NSURLResponse, NSData)
  case Error(NSError)
}

func processRequestResponse(response: NetworkResponse) {
  guard case let .Response(urlResp, data) = response,
    let httpResp = urlResp as? NSHTTPURLResponse
    where 200..<300 ~= httpResp.statusCode else {
      print("Invalid response, can't process")
      return
  }
  print("Processing \(data.length) bytes…")
}

for case

把for、case這兩個(gè)關(guān)鍵字聯(lián)合起來,能夠讓我們在迭代集合的時(shí)候,進(jìn)行模式匹配,這感覺就好像我們在for迭代中,使用了if case。我們先來創(chuàng)建一個(gè)Media類型的數(shù)組,數(shù)組中包括電影和圖書。

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),
  .Book(title: "Harry Potter and the Prisoner of Azkaban", author: "J.K. Rowling", year: 1999),
  .Movie(title: "Harry Potter and the Prisoner of Azkaban", director: "Alfonso Cuarón", year: 2004),
  .Movie(title: "J.K. Rowling: A Year in the Life", director: "James Runcie", year: 2007),
  .WebSite(urlString: "https://en.wikipedia.org/wiki/List_of_Harry_Potter-related_topics")
]

現(xiàn)在我們來完成這樣一個(gè)任務(wù),我們把集合中所有的電影信息打印出來:

for case let Media.Movie(title, _, year) in mediaList {
  print(" - \(title) (\(year))")
}

如果配合上where子句,我們會得到更加強(qiáng)大的能力,比方說我們只打印某一位導(dǎo)演的電影。

for case let Media.Movie(title, director, year) in mediaList where director == "Chris Columbus" {
  print(" - \(title) (\(year))")
}

百尺竿頭再進(jìn)一步

我們現(xiàn)在擴(kuò)展一下Media,讓它可以描述title和種類,我們用extension關(guān)鍵字。

extension Media {
  var title: String? {
    switch self {
    case let .Book(title, _, _): return title
    case let .Movie(title, _, _): return title
    default: return nil
    }
  }
  var kind: String {
    switch self {
    case .Book: return "Book"
    case .Movie: return "Movie"
    case .WebSite: return "Web Site"
    }
  }
}

現(xiàn)在我們打印一下mediaList中所有元素的title和kind

for case let (title?, kind) in mediaList.map({ ($0.title, $0.kind) })
  where title.hasPrefix("Harry Potter") {
    print(" - [\(kind)] \(title)")
}

這個(gè)代碼的可讀性并不是很高,我們先來簡單解釋一下上面這個(gè)代碼片段

  • 首先是map函數(shù)將 mediaList 映射成一個(gè)[(String?,String)]類型的數(shù)組。
  • 然后我們使用case let 進(jìn)行了title 與 kind的值綁定,因?yàn)槲覀冎该髁藅itle?所以要求數(shù)組元素中必須包含title
  • 最后使用where子句進(jìn)行條件表達(dá)式過濾。

因?yàn)榇a的可讀性決定了代碼了可維護(hù)性,所以寫出容易閱讀的代碼是至關(guān)重要的,我們其實(shí)可以使用guard關(guān)鍵字,讓上面的這個(gè)段代碼變得更加清晰簡潔(雖然長度會略長一些)。

for media in mediaList {
  guard let title = media.title else {
    continue
  }
  guard title.hasPrefix("Harry Potter") else {
    continue
  }
  print(" - [\(media.kind)] \(title)")
}

希望if case可以更多的出現(xiàn)在我們的代碼中,來讓我們的代碼更優(yōu)美。

本文參考

https://www.natashatherobot.com/swift-2-pattern-matching-with-if-case/

http://alisoftware.github.io/swift/pattern-matching/2016/05/16/pattern-matching-4/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容