search
LoginSignup
1

More than 3 years have passed since last update.

posted at

updated at

忘備録-Swiftのパターン

趣味でIOSアプリ開発をかじっていた自分が、改めてSwiftを勉強し始めた際に、曖昧に理解していたところや知らなかったところをメモしています。

参考文献

この記事は以下の書籍の情報を参考にして執筆しました。

switch文でwhere節を使う

func trashDate(weekly: Int, weekday: String){
  let week = (weekly, weekday)    // タプル型
  switch week {
  case (_, "月曜日"):
    print("燃えるゴミの日")
  case (let i, "木曜日") where i == 1 || i == 3 :    // where節の条件に一致する場合処理を実行
    print("燃えないごみの日")
  case let (i, j):
    print("第\(i)\(j)")
  }
}
trashDate(weekly: 4, weekday: "月曜日")    // 燃えるゴミの日
trashDate(weekly: 2, weekday: "木曜日")    // 第2週 木曜日
trashDate(weekly: 1, weekday: "木曜日")    // 燃えないごみの日
trashDate(weekly: 99, weekday: "hoge")    // 第99週 hoge

switch文でオプショナル型を使う


func  ageConfirmation(people: (String, Int?)) {
  switch people {
  case let (name, age?) where age >= 20:
    print("\(name),成人済み")
  case let (name, age?) where age < 20 && age >= 0:
    print("\(name),未成年")
  case (let name, nil) :
    print("\(name),年齢不詳")
  default:
    break
  }
}
ageConfirmation(people: ("hoge", 20))    //hoge,成人済み
ageConfirmation(people: ("fuga", 8))    //fuga,未成年
ageConfirmation(people: ("foo", nil))    //foo,年齢不詳
ageConfirmation(people: ("bar", -8))

列挙型のメソッド

enum Coin {
  case front, back
  func reverse() -> Coin{
    switch self {
    case .front:
      return .back
    case .back:
      return .front
    }
  }
}

let coin = Coin.back
print(coin)    // back
print(coin.reverse())    // front

値型の列挙型

enum Coin: Int {
  case front = 0, back    //backは1になる
  func reverse() -> Coin{
    switch self {
    case .front:
      return .back
    case .back:
      return .front
    }
  }
}
let coin = Coin.back
print(coin)    // back
print(coin.rawValue)    // 1
print(coin.reverse().rawValue)    //0

列挙型のケースを全て含むコレクション

enum Coin: Int, CaseIterable {
  case front = 0, back    //backは1になる
}

print(Coin.allCases)    // [CodeTest.Coin.front, CodeTest.Coin.back]
for elm in Coin.allCases{
  print(elm)    // front back
}

if-case文

let p = Payment.クレジット(120, true)

// pがクレジットカードかを知りたい
if p == .クレジット{    // error
  print("クレカ")
}

//  switch文でも書けるが少し面倒
switch p {
case .クレジット:
  print("クレカ")
default:
  break
}

//  if-caseを使う
if case .クレジット = p {
  print("クレカ")
}

for-in文でcaseパターンを使う場合

enum Payment {
  case クレジット(_ 残高:Int, _ 使用可能: Bool)
  case アプリ(_ 残高: Int, _ 還元率: Double = 0.02)
  case 現金
}

let paylist: [Payment] = [.クレジット(120, true), .アプリ(1120),
                              .現金, .クレジット(12000, true), .クレジット(99999, false),
                              .クレジット(1200, true)]

// 1100円以上の残高があり、使用可能なクレジットカードを取り出す
for case let .クレジット(money, b) in paylist where b == true && money >= 1100 {
  print(money)
}

// このように書くのと同じ
for t in paylist {
  switch t {
    case let .クレジット(money, b):
      if b == true && money >= 1100{
        print(money)
      }
    default:
      break
  }
}

再帰的な列挙型

// 再帰的に呼び出すcaseの前にindirectをつける
enum メッセージ : CustomStringConvertible{    // プロトコルを採用
  case 文書(_ 差出人: String, _ 文章: String)
  case 添付(_ 差出人: String, _ データ: String)
  indirect case 転送(_ 差出人: String, メッセージ)
  var description: String{
    switch self {
    case let .文書(from, str):
      return from + " : " + str
    case let .添付(from, data):
      return from + " : " + data
    case let .転送(from, message):
      return from + " : " + " <- \(message)"
    }
  }
}

// XcodeでFIXしたとき
indirect enum メッセージ : CustomStringConvertible{    // プロトコルを採用
  case 文書(_ 差出人: String, _ 文章: String)
  case 添付(_ 差出人: String, _ データ: String)
  case 転送(_ 差出人: String, メッセージ)
  var description: String{
    switch self {
    case let .文書(from, str):
      return from + " : " + str
    case let .添付(from, data):
      return from + " : " + data
    case let .転送(from, message):
      return from + " : " + " <- \(message)"
    }
  }
}
let m1 = メッセージ.文書("hoge", "Hello")
let m2 = メッセージ.転送("fuga", m1)
let m3 = メッセージ.転送("foo", m2)
print(m1)    // hoge : Hello
print(m2)    // fuga :  <- hoge : Hello
print(m3)    // foo :  <- fuga :  <- hoge : Hello

パターンマッチ演算子

Swiftのパターンマッチ :
スクリプト言語などが持っている文字列と正規表現のマッチングではない。

どの構造が何に対応するかに関してのルールに基づくデータ構造の対応づけ

~= : パターンマッチ演算子

let hoge = Coin.front
print(hoge ~= Coin.front)    // true

パターンマッチ演算子のルールを追加
ただし、パターンマッチ演算子の新たな定義を追加すると、switchやif-case文の挙動に直接影響するので必要性について考えること。

enum Coin: Int {
  case front, back
  func reverse() -> Coin{
    switch self {
    case .front:
      return .back
    case .back:
      return .front
    }
  }
}
// パターンマッチ演算子の定義を追加
func ~= (c: Coin, s: String) -> Bool{
  "\(c)" == s
}
let coin = Coin.front
print(coin ~= "front")    // true
print(coin.reverse() ~= "front")    // false

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1