2020/2/2 Swift パターン(Patterns)

 


識別子パターン(identifier pattern)

識別子パターンはあらゆる値とマッチし、マッチした値を変数名・定数名と結び付けます。例えば、下の定数の宣言ですが、someValueは識別子パターンで、Int型の42とマッチします。

let someValue = 42

マッチが成功すると、42という値は定数名someValueと結び付けられます(代入されます)。

定数宣言、変数宣言の左側が識別子パターンである時、その識別子パターンは暗黙的なバリューバインディングパターンのサブパターンです。


バリューバインディングパターン(value-binding pattern)

バリューバインディングパターンはマッチした値を変数名・定数名と結び付けます。バリューバインディングパターンでマッチした値を定数名と結びつけるにはletキーワードを最初に付けます。マッチした値を変数名と結びつけるにはvarキーワードを最初に付けます。

バリューバインディングパターンの一部である識別子パターンは、マッチした値を新しい変数名・定数名と結び付けます。例えば、タプルの要素を分解して各要素の値を対応する識別子パターンと結びつけることができます。

let point = (3, 2)
switch point {
    // pointの要素をxとyに結びつける。
case let (x, y):
    print("The point is at (\(x), \(y)).")
}
// Prints "The point is at (3, 2)."

上のサンプルでは、letが、タプルパターン(x,y)の中のそれぞれの識別子パターンに分配します。この挙動のため、switch文のケースである

case let (x,y):

case (let x, let y):

は同じ値にマッチします。


タプルパターン(tuple pattern)

タプルパターンはカンマで区切られた0個、あるいはそれ以上の要素を丸かっこで囲んだリストです。タプルパターンは対応するタプル型とマッチします。

型注釈を使用することで、マッチするタプル型の種類を制約することができます。例えば、定数宣言

let (x,y):(Int,Int)=(1,2)

の中で、

(x,y):(Int,Int)

のようなタプルパターンを記述すると、そのタプルパターンは、両方の要素がInt型のタプル値にのみマッチします。

工事中🏗


列挙型ケースパターン(enumeration case pattern)

列挙型ケースパターンは既存の列挙型のケースとマッチします。列挙型ケースパターンは

  • switch文のcaseラベル
  • 条件付きif,while,guard文
  • for-in文

で登場します。

工事中🏗

列挙型ケースパターンは、オプショナル型の列挙型ケースにもマッチします。


オプショナルパターン

 

 


タイプキャストパターン

タイプキャストパターンは、

  • isパターン
  • asパターン

の二つがあります。isパターンはswitch文のcaseラベルにのみ登場します。isパターン、asパターンは以下のように記述します。

is type

pattern as type

isパターンは、照会対象の値(switchの後ろの値)の実行時の型が、isパターンの右側に指定した型と同じ型であれば、あるいは指定した型のサブクラスと同じ型であれば「マッチした」ことになります。

asパターンは照会対象の値(switchの後ろの値)の実行時の型が、isパターンの右側に指定した型と同じ型であれば、あるいは指定した型のサブクラスと同じ型であれば「マッチした」ことになります。マッチした場合、マッチした値の型が、asパターンの右側で指定された型へとキャストが行われます。

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}

var things = [Any]()

things.append(1)
things.append(1.00000)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
var nnn=0
for thing in things {
    nnn+=1
    print("""
        
\(nnn)番目の要素の型は\(type(of:thing));
""")
    switch thing {
    case 1 as Int:
        print("11111zero as an Int")
        
    case 1 as Double:
        print("22222zero as a Double")
        
    case let someInt as Int:
        print("33333an integer value of \(someInt)")
        
    case let someDouble as Double where someDouble > 0:
        print("444444a positive double value of \(someDouble)")
        
    case is Double:
        print("55555some other double value that I don't want to print")
        
    case let someString as String:
        print("66666a string value of \"\(someString)\"")
        
    case let (x, y) as (Double, Double):
        print("77777an (x, y) point at \(x), \(y)")
        
    case let movie as Movie:
        print("88888a movie called \(movie.name), dir. \(movie.director)")
        
    case let stringConverter as (String) -> String:
        print(stringConverter("Michael"))
        
    default:
        print("something else")
    }
}
1番目の要素=Int;
11111zero as an Int
        
2番目の要素=Double;
22222zero as a Double
        
3番目の要素=Int;
33333an integer value of 42
        
4番目の要素=Double;
444444a positive double value of 3.14159
        
5番目の要素=String;
66666a string value of "hello"
        
6番目の要素=(Double, Double);
77777an (x, y) point at 3.0, 5.0
        
7番目の要素=Movie;
88888a movie called Ghostbusters, dir. Ivan Reitman
        
8番目の要素=(String) -> String;
Hello, Michael

 

 


式パターン(Expression Pattern)

式パターン(expression pattern)は、式の値を表現します。式パターンはswitch文のcaseラベルにのみ登場します。

式パターンで表現されている式(各caseの式)は、インプットされた式(switch

の後ろの式)の値と比較されます。Swift標準ライブラリの~=演算子を用いて比較されます。~=演算子を用いて比較した結果、~=演算子がtrueを返した場合、マッチしたことになります。デフォルトでは、~=演算子は同じ型の二つの値を==演算子を用いて比較します。式パターンで範囲の値を照会(マッチするか調べる)することもできます。その値が範囲に含まれるか、以下のサンプルのような感じです。

let point = (1, 2)
switch point {
case (0, 0):
    print("(0, 0) is at the origin.")
case (-2...2, -2...2):
    print("(\(point.0), \(point.1)) is near the origin.")
default:
    print("The point is at (\(point.0), \(point.1)).")
}
// Prints "(1, 2) is near the origin."

式パターンについて独自のマッチングパターンを定義するため、~=演算子をオーバーロード(上書き定義)することもできます。例えば、pointという式を、座標の文字列表現と比較するように、上のサンプルを書き換えたのが下のサンプルです。

// Overload the ~= operator to match a string with an integer.
func ~= (pattern: String, value: Int) -> Bool {
    return pattern == "\(value)"
}
switch point {
case ("0", "0"):
    print("(0, 0) is at the origin.")
default:
    print("The point is at (\(point.0), \(point.1)).")
}
// Prints "The point is at (1, 2)."

 

 

 

参考

https://docs.swift.org/swift-book/ReferenceManual/Patterns.html

コメントを残す

メールアドレスが公開されることはありません。