2020/2/14 Swift->Control Flow->While Loops

While Loops

whileループは条件式がfalseになるまでstatementsを実行する制御です。イテレーションが始まる前にイテレーションの回数がわからないような場合にwhileループを使用するのが適しています。Swiftは二つの種類のwhileループを提供します。

  • while文はループの最初に条件式を評価します。
  • repeat-while文はループの終わりに条件式を評価します。

while文

whileループは一つの条件式をループの最初に評価します。条件式がtrueと評価された場合、条件式がfalseと評価されるまで実行文が繰り返し実行されます。

while condition {
    statements
}

下のサンプルはシンプルなゲーム「Snakes and Ladders(へびとはしご)」です。

 

ルールは以下の通りです。

ボードには25のマスがあります。ゲームの目的(ゴール)は25マス目に到達、あるいは25マス目を超えることです。

  • スタート地点は「0マス目」であり、ボードの外にあります。
  • それぞれのターンで六面のサイコロを振り、図で示す道順に従いサイコロの結果の数だけ進みます。
  • 進んだ先にはしごの下端があれば、はしごを登ってはしごの上端まで進めます。
  • 進んだ先にへびの頭があれば、へびに食われてへびの尻尾まで戻されます。

ゲームのボードはInt型の配列で表現されます。ゲームボードのサイズは定数finalSquareの値に基づきます。ボードを表現する配列boardのイニシャライズにfinalSquareが使用されます。またこの後登場する勝利条件の判定にもfinalSquareが使用されます。配列boardは、プレーヤーのスタート地点も含めて全部で26(25ではなくて)のInt型の値0でイニシャライズされます。

let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)

いくつかのマス目は、へびとはしごを表現するために、特別に値をセットします。はしごの入り口のマス目には正の数値をセットしてボードを進めることを表現します。へびの頭のマス目には負の数値をセットしてボードを戻らなければならないことを表現します。

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

board[03]ははしごの入り口なので、「+08」をセットしてboard[11]に進めることを表します。値とステートメントを揃えるために、単項プラス演算子(+ i)が単項マイナス演算子(-i)とともに明示的に使用され、10未満の数値にはゼロが埋め込まれます。 (どちらのスタイルの手法も厳密には必要ありませんが、よりきれいなコードになります。)

var square = 0
var diceRoll = 0
while square < finalSquare {
    // roll the dice
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    // move by the rolled amount
    square += diceRoll
    if square < board.count {
        // if we're still on the board, move up or down for a snake or a ladder
        square += board[square]
    }
}
print("Game over!")

 

工事中🏗

 


No Implicit Fallthrough

CやObjective-Cのswitch文と違い、Swiftのswitch文はデフォルトで、マッチしたケースのブロックの実行が終わるとswitch文自体から抜けます。ですから各ケースのブロックの最後にbreakを明示的に記述する必要がありません

各ケースのボディは少なくとも一つの文を含んでいる必要があります。次のサンプルは一番目のケースが空ですから許されません。

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // ←文が一つも無いのでエラー
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
//コンパイルエラー発生

Cのswitch文とは違い、上記のサンプルのswitch文は”a”と”A”の両方にマッチすることはありません。上記のサンプルは

ケース”a”

に一つも実行すべき文が無いのでコンパイルエラーが発生します。この挙動によりミスによるフォールスルーを回避でき、意図がわかりやすい安全なコードが書けます。

一つのケースで”a”と”A”の両方にマッチさせたい場合、以下のようにカンマで区切って記述します。

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// Prints "The letter A"

 


範囲によるマッチング(Interval Matching)

工事中🏗

 


Tuples

工事中🏗

 


バリューバインディング(Value Bindings)

switch文のケースは値に対して、一時的な定数名、変数名により名前をつけることができます(定数・変数にその値がセットされる)。そしてその定数・変数ケースのボディ内で使用できます。ケースのボディ内で一時的な定数・変数と値が結び付けられますので、この挙動はバリューバインディングとして知られています。

下のサンプルは 座標(x,y)を(Int,Int)型のタプルで表現しています。そして下のグラフにカテゴライズします。

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}
// Prints "on the x-axis with an x value of 2"

 

このサンプルでswitch文は、座標が

  • x軸上にある
  • y軸上にある
  • それ以外(どちらの軸の上にも無い)

のように場合分けします。

switch文の三つのケースはプレースホルダーとして定数xと定数yを宣言し、anotherPointからタプルの片方、あるいは両方の値を受け取ります。一番目のケース

case (let x,0)

は、y座標が0のあらゆる座標とマッチし、一時的な定数xに「anotherPointのx座標の値」をセットします。同様に二番目のケース

case (0,let y)

は、x座標が0のあらゆる座標とマッチし、一時的な定数yに「anotherPointのy座標の値」をセットします。

一時的な定数が宣言されると、その定数をそのケースのコードブロック内で使用できます。サンプルでは定数の値を表示しています。

このサンプルのswitch文はdefaultケースがありません。最後のケースである

case let (x,y)

は、二つのプレースホルダーx,yを持つタプルを宣言しており、これはあらゆる座標とマッチします。anotherPointは常に二つの値を持つタプルですので、このケースは、それよりも上のケースでマッチしなかった全ての値とマッチします。ですので、defaultケースを用意しなくてもswitch文の網羅性が確保されます。


Where

switch文のケースではwhere節を使用して追加的な条件についてチェックすることができます。

下のサンプルは(x,y)座標を以下のように分類します。

 

工事中🏗

 


ケースの合成(Compound Cases)

複数のケースが同じボディを有する場合

let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
     "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}
// Prints "e is a vowel"

 

 

 

参考

https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html

コメントを残す

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