制御文

Swiftの制御文には他の一般的な言語と同様、if、for、while、switch等があります。

if

if文は次のような構造になります。


if 条件1 {
    条件1がtrueの場合に実行する処理
} else if 条件2 {
    条件2がtrueの場合に実行する処理
  :
} else {
    上のどの条件にも合致しなかった場合に実行する処理
}

if文の条件はtrueかflaseを返すBool型でなければなりません。Int型や文字列型等はif文の条件として直接使用することはできません。

{}は必須です。else以降は不要なら省略できます。条件の前後を()で囲む必要はありませんが、囲むこともできます。


var engine: Int?  // 排気量

if engine <= 50 {
    print("原付バイク")
} else if engine <= 125 {
    print("小型バイク")
} else if engine <= 400 {
    print("中型バイク")
} else {
    print("大型バイク")
}

if engine == 750 {
    print("ナナハン")
}
Swiftの論理演算は短絡評価です。例えば、Boolを返す次のようなfuncA()とfuncB()という関数を呼び出すif文があった場合、次の例では、funcA()の評価がfalseなので、if分の条件が偽となり、funcB()は実行されません。

func funcA() -> Bool {
    print("funcA")
    return false
}

func funcB() -> Bool {
    print("funcB")
    return true
}

if funcA() && funcB() {
    // 実行されない
}

また、同様に、次の例では、funcA()からtrueが返された時点でif文の条件が真となり、funcB()は実行されません。


func funcA() -> Bool {
    print("funcA")
    return true
}

func funcB() -> Bool {
    print("funcB")
    return false
}

if funcA() || funcB() {
    // 実行される
}

funcA()やfuncB()の中で副作用のある処理(クラスのメンバ変数やグローパル変数の書き換え等)を行うと結果が推測しにくくなるので、そのような書き方は避けるべきです。

for

for文には2通りの書き方があります。

1つは、C言語と似た書き方で、初期処理、ループの継続条件、ループの後処理を書く書き方です。


for 初期処理; ループの継続条件; ループの後処理 {
    処理
}

ループの継続条件がtrueの間、ループが実行されます。通常、初期処理ではループ変数の初期化を行い、ループの後処理で変数のインクリメント等を行います。


let party = ["勇者", "戦士", "魔法使い", "僧侶"]
for var index = 0; index < party.count; ++index {
    print(party[index])
}

ループの中でcontinueを使うと途中で次のループ処理へ移ることができます。また同様にbreakを使うと処理を中断してループを抜けることができます。


let party = ["勇者", "戦士", "魔法使い", "僧侶"]
for var index = 0; index < party.count; ++index {
    if index < 1 { continue }
    if index > 2 { break }
    print(party[index])
}
/*
戦士
魔法使い
*/

上のindexは、forループの中でのみ参照可能です。forループの外で参照するには、次のようにループの外側で変数を宣言する必要があります。


let party = ["勇者", "戦士", "魔法使い", "僧侶"]
var index: Int
for index = 0; index < party.count; ++index {
    if index < 1 { continue }
    if index > 2 { break }
    print(party[index])
}
print("index=\(index)")

もう1つのfor文の書き方は、forin を使った書き方です。


for 要素 in 要素の取り出し元 {
    処理
}

次のように範囲演算子と共に使うことができます。for の後の変数は定数となります。letは不要です。但しforループの外で参照することはできません。


for index in 1...5 {
    // indexは定数
    print("index = \(index)")
}
/* 実行結果
index = 1
index = 2
index = 3
index = 4
index = 5
*/

let party = ["勇者", "戦士", "魔法使い", "僧侶"]
for index in 0 ..< party.count {
    print(party[index])
}
/* 実行結果
勇者
戦士
魔法使い
僧侶
*/

要素を使用しない場合は、_(下線)で置き換えることができます。


for _ in 0 ..< party.count {
    print("Hello")
}

配列やディクショナリはfor〜inを使ってループ処理することができます。


let party = ["勇者", "戦士", "魔法使い", "僧侶"]
for chara in party {
    print(chara)
}

let items = ["りんご": 100, "みかん": 300, "バナナ": 150]
// ディクショナリの場合は、キーと値のペアのタプルが取り出される
for (name, price) in items {
    print("\(name): \(price)円")
}
// 1つの変数に受け取ることも可能
for item in items {
    print("\(item.0): \(item.1)円")
}

こちらも、使用しない要素は_(下線)にできます。


let items = ["りんご": 100, "みかん": 300, "バナナ": 150]
for (name, _) in items {
    print(name)
}

while

while文には、ループの最初で条件を判定する書き方と、ループの最後で条件を判定する書き方があります。

ループの最初で判定する書き方は次のようになります。


while ループの継続条件 {
    処理
}

/* 
  戦闘関数
  自分のダメージと相手のダメージをタプルで返す
*/
func fight() -> (Int, Int) {
    var myDamage: Int       // 自分のダメージ
    var enemyDamage: Int    // 相手のダメージ
    :
    return (myDamage, enemyDamage)
}

var myHitPoint: Int     // 自分のHP
var enemyHitPoint: Int  // 相手のHP
// 戦闘処理
while 0 < myHitPoint && 0 < enemyHitPoint {
    let (myDamage, enemyDamage) = fight()
    print("敵に\(enemyDamage)のダメージを与えた。")
    print("\(myDamage)のダメージを受けた。")
    myHitPoint -= myDamage
    enemyHitPoint -= enemyDamage
}

for文と同様に、continueやbreakで処理の継続や中断ができます。


while 0 < myHitPoint {
    let (myDamage, enemyDamage) = fight()
    print("敵に\(enemyDamage)のダメージを与えた。")
    if enemyHitPoint - enemyDamage < 0 {
        print("あなたの勝ち!")
        break
    }
    print("\(myDamage)のダメージを受けた。")
    myHitPoint -= myDamage
    enemyHitPoint -= enemyDamage
}

ループの最後に判定する書き方は次のようになります。


do {
    処理
} ループの継続条件

ループの最初に判定する書き方の場合、条件によってはループの中の処理が一回も実行されない場合がありますが、ループの最後に判定する書き方の場合、ループの中の処理が最低1回は実行されます。


do {
    let (myDamage, enemyDamage) = fight()
    print("敵に\(enemyDamage)のダメージを与えた。")
    print("\(myDamage)のダメージを受けた。")
    myHitPoint -= myDamage
    enemyHitPoint -= enemyDamage
} while 0 < myHitPoint && 0 < enemyHitPoint

forやwhileの前にラベルを書いて、continueやbreakの対象として指定することができます。内側のループから外側のループへ戻す場合に便利です。


let text: String = "「りんご」 「みかん」 「バナナ」"
// 「 と 」で括られた文字列の切り出し
outerLoop: for var index = text.startIndex; index != text.endIndex; index = index.successor() {
    var ch = text[index]
    if ch == "「" {
        var fruit = ""
        while true {
            index = index.successor()
            if index == text.endIndex {
                break outerLoop
            }
            ch = text[index]
            if ch == "」" {
                print(fruit)
                continue outerLoop
            }
            fruit += ch
        }
    }
}
/*
りんご
みかん
バナナ
*/

switch

switch文を使うと、値に応じた処理内容を記述することができます。値のパターンが多い場合、if文を使うより見通しよく書けます。C言語やJavaのswitch文と似ていますが、Swiftのswitch文はより柔軟な比較判定が可能です。

switch文の基本的な構造は次のようになります。


switch 比較対象(変数や関数の戻り値等) {
case 値1:
    値1に合致する場合の処理
case 値2, 値3:
    値2又は値3に合致する場合の処理
  :
default:
    上のどの条件にも合致しなかった場合の処理
}

switchに比較する対象となる要素を書き、想定する値の条件をcaseに書きます。


var coin: Int  // 硬貨(円)
  :
switch coin {
case 1, 10, 100:
    print("穴無し硬貨")
case 5, 50:
    print("穴開き硬貨")
default:
    print("不明")
}

C言語のswitchと異なり、caseの最後にbreakを書く必要はありません。逆に複数のcaseで同じ処理をしたい場合は、次へ移るcaseの最後にfallthrough と書きます。


var coin: Int // 硬貨(円)
  :
switch coin {
case 1:
    fallthrough
case 10:
    fallthrough
case 100:
    print("穴無し硬貨")
case 5:
    fallthrough
case 50:
    print("穴開き硬貨")
default:
    print("不明")
}

数値以外の型も比較対象として使用することができます。


var signal: String  // 信号機
:
switch signal {
case "青":
    print("進め")
case "黄":
    print("注意")
case "赤":
    print("止れ")
default:
    print("故障?")
}

比較対象が取り得る全ての値をcaseに網羅する必要があります。抜けがあるとコンパイルエラーになります。上の例では、Int型もString型もcaseに記述された以外の値も取り得るので、default:の記述が無いとエラーになります。

次の様にenum型の判定にも使用することができます。この場合、全ての値を網羅できているのでdefault:は不要です。


// 信号機
enum Signal {
    case Blue   // 青
    case Yellow // 黄
    case Red    // 赤
}
var s: Signal
  :
switch s {
case .Blue:
    print("進め")
case .Yellow:
    print("注意")
case .Red:
    print("止れ")
}

caseに何も処理が記述されていないとエラーになります。


switch s {
case .Blue:
    print("進め")
case .Yellow:
    /* エラー */
case .Red:
    print("止れ")
}

何も処理したくない場合は、breakだけ記述します。


switch s {
case .Blue:
    print("進め")
case .Yellow:
    break
case .Red:
    print("止れ")
}

次の様にcaseで範囲を指定することもできます。


var num: Int
  :
switch abs(num) {   // absは絶対値を返す関数
case 0:
    print("ゼロ")
case 1..<10:
    print("1桁")
case 10..<100:
    print("2桁")
case 100..<1000:
    print("3桁")
default:
    print("4桁以上")
}

whileを使って条件を指定することもできます。


switch abs(num) {   // absは絶対値を返す関数
case let n where n == 0:
    print("ゼロ")
case let n where n < 10:
    print("1桁")
case let n where n < 100:
    print("2桁")
case let n where n < 1000:
    print("3桁")
default:
    print("4桁以上")
}

複数のcaseに該当する場合、上から順に評価されて最初に該当するcaseの内容が実行され、それ以降の該当するcaseの内容は実行されません。


var i = 10

switch i {
case let j where j < 10:
    print("i < 10")
case let j where j < 100:
    print("i < 100")     // ここの内容だけ実行される
case let j where j < 1000:
    print("i < 1000")
default:
    print("i <= 1000")
}
/*
 実行結果
 i < 100
*/

次はタプルをswitch文で判定する例です。


var vehicle: (Int, Int?) // タイヤの数と排気量
vehicle = (2, 125)

switch vehicle {
case (1, _):      // 不要な変数は_(下線)を指定して無視
    print("一輪車")
case (2, nil):
    print("自転車")
case let (2, engine):
    switch engine! {
    case let e where e <= 0:
        print("バイク:排気量エラー")
    case 1...50:
        print("原付バイク")
    case 51...125:
        print("小型バイク")
    case 126...250:
        print("中型バイク")
    default:
        print("大型バイク")
    }
case (3, _):
    print("三輪車")
case let (4, engine) where engine != nil:
    switch engine! {
    case let e where e <= 0:
        print("自動車:排気量エラー")
    case let e where e <= 660:
        print("軽自動車")
    default:
        print("普通車")
    }
case let (tire, engine):
    print("不明な乗り物(\(tire)輪、排気量:" + (engine == nil ? "-" : "\(engine!)cc")  + ")")
}

通常、caseの条件文にはletを使いますが、varを使って、値を変更することも可能です。


let num: Int = 10

switch num {
case var n where n == 10:
    n += 20
    print(n)
default:
    break
}