モードマッチング第2弾:メタグループ、range、タイプ

6680 ワード

作者:Olivier Halligon,原文リンク,原文日付:2015-03-30訳者:小鍋;校正:saitjr;下書き:shanks
前の論文では,switchを用いて列挙を基本的なモードマッチングすることを見た.では、列挙を除く他のタイプに対してswitchを使用してモードマッチングを行うとどうなるのでしょうか.
メタグループのパターンマッチング
Swiftでは,switchはObjCのように整数または列挙のみをマッチングできるわけではない.
実際、switchを使用して、メタグループを含む多くのタイプをマッチングすることができます(ただし、限定されません).
これは、複数のデータを1つのメタグループに組み合わせるだけで、複数のデータを一度に一致させることができることを意味します.たとえば、CGPointがあり、この点が座標軸上にあるかどうかを確認したい場合は、switchを使用して.x.yのプロパティを一致させることができます.

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

前の文書で使用した_ワイルドカードと、4番目のcaseで使用した(let x, let y)は、変数をバインドし、whereを使用して等しいかどうかを確認することができることに注意してください.
Caseは順番に判断しています
さらに、switchは、caseモードで指定された順序で評価を判断し、最初に満たされたcaseに一致した後に飛び出すことに注意されたい.CとObjective-Cとは異なり、breakキーワード1を使用する必要はありません.
これは、上記のコードにおいて、座標が(0, 0)であれば、最初のcaseに一致して"On the origin!"が印刷され、(0, _)(_, 0)が一致してもマッチングの条件に合致しないことを意味する.最初のマッチングの後に飛び出したからです.
文字列と文字
なぜメタグループに止まるのですか?Swiftでは、文字列や文字など、多くのオリジナルタイプを一致させるためにswitchを使用することもできます.

let car: Character = "J"
switch car {
  case "A", "E", "I", "O", "U", "Y": print("Vowel")
  default: print("Consonant")
}

カンマで区切られた複数のモードを使用してマッチングを行うことができ、これらのモードに一致するマッチング(ここではすべてのアクセントアルファベットに一致する)が同じコードを実行することができます.これにより、多くの重複コードを書くことを避けることができます.
Range
Rangeはモードマッチングにも役立ちます.注意してください.Rangeは、Tタイプのstartおよびendメンバーを含む汎用タイプであり、TForwardIndexTypeでなければなりません.これには、IntおよびCharacterを含む多くのタイプが含まれる.
?Range(start: 1900, end: 2000)を使用してrangeを明示的に宣言してもよいし、シンタックスオペレータ..<(最後の数endを含まない)または...(最後の数endを含む)を使用してもよいので、上記のrangeを1900..<2000と書くこともできます(さらに読みやすい)
では、switchでどのように使用しますか?実はかなり簡単で、caseモードでrangeを使って値がこの範囲内に落ちているかどうかを判断します!

let count = 7
switch 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")
}
caseの中でIntの整数値とRangeの値を混用していることがわかる.このような使用には問題はありません.私たちが可能なすべての状況をカバーすることを保証すれば.Intは最も一般的なrangeタイプですが、他のForwardIndexTypeタイプも使用できます.Character !上に書いたコードを覚えていますか?句読点やA-Z以外の文字に対しても「Consonant」と印刷されるという問題があります.この問題を解決しましょう2(小文字も追加しました):

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"
  }
}
print("Jules Verne".characters.map(charType))
// ["Consonant", "Vowel", "Consonant", "Vowel", "Consonant", "Other", "Consonant", "Vowel", "Consonant", "Consonant", "Vowel"]

を選択します.
これですべては順調ですが、私たちはもっと進むことができますか?答えはもちろん問題ありません.パターンマッチングを...タイプ上!
ここでは、3つの構造体を定義し、同じプロトコルを遵守します.

protocol Medium {
  var title: String { get }
}
struct Book: Medium {
  let title: String
  let author: String
  let year: Int
}
struct Movie: Medium {
  let title: String
  let director: String
  let year: Int
}
struct WebSite: Medium {
  let url: NSURL
  let title: String
}

// And an array of Media to switch onto
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)
]

そして、Mediumに対してswitchのモードマッチングを使用して、BookMovieに対して異なることをさせるにはどうすればいいのでしょうか.簡単で、パターンマッチングにasisを使います!

for medium in media {
  // The title part of the protocol, so no need for a switch there
  print(medium.title)
  // But for the other properties, it depends on the type
  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:
    print("A WebSite with no date")
  default:
    print("No year info for \(medium)")
  }
}
BookおよびMovieで使用されるasについては、それらが特定のタイプであるかどうかを決定する必要があり、もしそうであれば、変換されたタイプを定数(let bまたはlet m)に割り当てる必要があります.なぜなら、私たちは後でこの定数3を使用するからです.
一方、WebSiteについてはisしか使用していません.mediumWebsiteタイプかどうかを調べるだけです.定数に変換して保存していません(print文で使用する必要はありません).これはcase let _as Websiteを使用するのと少し似ています.Websiteタイプであるかどうかだけに関心を持っており、オブジェクトの値は必要ありません.
?注意:swtichマッチングでasおよびisを使用する必要がある場合、ここではコード異臭が存在する可能性があります.例えば、上記の特定の例では、protocol MediumreleaseInfo: String { get }属性を追加することは、switchを使用して異なるタイプをマッチングするよりも良いです.
次のステップ
次のセクションでは、パターンマッチングに直接使用できるカスタムタイプを作成する方法を学び、より多くの構文糖を探索し、switch文の外でパターンマッチングを使用する方法と、より複雑なマッチング式を参照します.待ちきれないでしょう.
  • は、fallthroughキーワードを使用して、評価判定を次のcaseに流すことができる.しかし、実際にこのキーワードを使うシーンは少なく、あまり遭遇しません.
  • もちろん、この文字列の分析方法は最良ではなく、推奨に値するものではありません.Unicode文字やローカライズはこれよりずっと複雑だからです.このような機能はNSCharacterSetを使用して、現在のNSLocaleがどのアルファベットを母音と定義しているか(「y」は母音ですか?「
  • は、switch式とよく似ていますが、Rangeが特定のタイプに変換できる場合、それらはすべて1つの変数にバインドされます.しかし、モードマッチングではif let b = medium as? Bookではなくmediumを使用します.それらのメカニズムは似ているが、それらの意味は異なる(「タイプ変換を試み、失敗した場合はas」vs「このモードがこのタイプに一致するかどうかを判断する」)
  • .
    本文はSwiftGG翻訳グループから翻訳して、すでに作者の翻訳の授権を得て、最新の文章は訪問して下さいhttp://swift.gg.