Swift 6.0 beta 日本語化計画 : Swift 6.0 beta
フロー制御
Swift は 様々なフロー制御文を提供しています。これらはタスクを複数回実行できる while ループを含み、 if、guard と switch 文は、一定の条件に基づいてコードの異なる分岐を実行し、そして break や continue のような文は、コード内の別のポイントに実行のフローを転送します。Swift は for-in ループを提供し、それによって簡単に、配列、dictionary、範囲、文字列、および他のシーケンスを反復処理できます。Swift はまた、現在のスコープを離れるときに実行されるコードを包み込む defer 文も提供します。
Swift の switch 文も、対応する多くの C に似た言語よりもとても強力と考えられます。Case は、間隔の一致、タプル、特定の型へのキャストなどを含む、さまざまなパターンに一致する事ができます。switch の case 内の一致した値は、case の本体内で使用するための一時的な定数または変数に結合することができ、複雑な一致条件は、それぞれの case について where 句で表すことができます。
配列内の項目、数字の範囲、または文字列内の文字のような、シーケンスを反復処理するため for-in ループを使用して下さい。
以下の例では for-in ループを使用して、配列内の項目を反復処理しています。
また、dictionary を繰り返し処理して、そのキー値のペアにアクセスすることもできます。dictionary が反復処理されるときに dictionary の各項目は (key, value) タプルとして返され、for-in ループの本体内で使用する明示的に名前が付けられた定数として (key, value) タプルのメンバーを分解できます。以下のコード例では、dictionary のキーは animalName という定数に分解され、dictionary の値は legCount という定数に分解されます。
Dictionary の内容は本質的に順序付けされておらず、それらを反復処理しても、それらが取得される順序は保証されません。特に、Dictionary に項目を挿入する順序は、それらが反復処理される順序を定義しません。配列と dictionary の詳細については、コレクション型 を参照してください。
数値範囲で for-in ループを使用することもできます。以下の例では、5倍の表の最初のいくつかのエントリを印刷します。
閉鎖範囲演算子(...)の使用によって示される、反復処理されるシーケンスは、1 から 5 の数値の範囲です。index の値は、範囲内の最初の数(1)に設定され、ループ内の文が実行されます。この場合、ループは、index の現在値の5倍の表からエントリを印刷する、一つの文だけを含んでいます。文が実行された後、index の値は範囲の 2 番目の値(2)を含むように更新され、print(_:separator:terminator:) 関数が再び呼び出されます。範囲の最後に到達するまで、このプロセスが続きます。
上記の例では、index は、その値がそれぞれのループの繰り返しの開始時に自動的に設定される定数です。このように、index は使用される前に宣言する必要はありません。これは、let 宣言キーワードを必要とせずに、ループ宣言内でそれを含むことにより、簡単に暗黙的に宣言されます。
シーケンスからの各々の値を必要としない場合は、変数名の代わりにアンダースコアを使用して、値を無視できます。
上記の例では、1つの数値に別の数を累乗した値を計算(この場合は 3 の10 乗)します。これは、1(すなわち 3 の 0 乗) から始まり、10回、1 から始まり 10 で終わる閉鎖範囲を使用して 3 を乗算します。この計算では、個々のカウンタ値は各々の回のループ中には必要はなく、コードは単にループを正しい回数実行する必要があります。アンダースコア文字 (_)はループ変数の代わりに使用され、個々の値は無視され、ループの各繰り返し中に現在値へのアクセスを提供しません。
状況によっては、両方の端を含む閉じた範囲を使用したくない場合もあります。時計盤上に 1 分ごとに目盛りを描くことを考えてください。0 分から開始して 60 目盛りを描きたいとします。下限を含めるが上限は含まない半開放範囲演算子(..<) を使用して下さい。範囲の詳細については、範囲演算子 を参照してください。
一部のユーザーは、彼らの UI で目盛りの数を減らしたいと思うかも知れません。代わりに 5 分ごとに 1 つのマークを好むかも知れません。stride(from:to:by:) 関数を使用して、不要なマークをスキップしましょう。
stride(from:through:by:) を代わりに使用すると、閉じた範囲も使用できます。
上記の例では、for-in ループを使用して、範囲、配列、辞書、および文字列を反復処理しています。ただし、この構文を使用して、独自のクラスやコレクション型を含む 任意の コレクションを反復処理できますが、それらの型が Sequence プロトコルに準拠している場合に限ります。
while ループは条件が false になるまで一連の文を実行します。これらの種類のループは、最初の繰り返しが始まる前に繰り返しの回数が知られていないときに一番よく使用されます。Swift は、2種類の while ループを提供しています。
while ループは、単一の条件を評価することによって始まります。条件が true の場合、条件が false になるまで、一連の文が繰り返されます。
while ループの一般的な形式は以下のとおりです。
この例では、蛇と梯子 (雨どいと梯子 としても知られています) の簡単なゲームを遊びます:
このゲームのルールは以下のとおりです:
このゲームボードは、Int 値の配列によって表されます。そのサイズは、この例の後の方では勝利条件をチェックすることにも使いますが、配列を初期化するために使用される finalSquare という定数に基づいています。プレイヤーはボードを "ゼロ番目の正方形" で開始するので、ボードは 25個でなく、26個のゼロの Int 値で初期化されます:
その後、いくつかの正方形は、ヘビと梯子の、より特殊な値に設定されます。梯子の下のある正方形には、ボードを上に移動するように正の数を持たせ、ヘビの頭がある正方形には、ボードを下に移動するように負の数を持たせます:
正方形 3 は、正方形 11 まで上に移動する、梯子の下を含んでいます。これを表すために、board[03] は +08 に等しく、整数値 8 (3 と 11 の差)と同等です。値と文が合うように、単項プラス演算子(+i)は単項マイナス演算子(-i)とバランスを取るため、また 10 より少ない数字は、ゼロで埋められます。(どちらの書式のテクニックとも、厳密には必要でありませんが、それらにより、コードがすっきりします。)
上記の例では、サイコロを振るために、非常に簡単なアプローチを使用しています。乱数発生の代わりに、 0 の diceRoll 値で始まります。while ループを通るごとに、diceRoll は、ひとつ増分された後、大きくなりすぎていないかどうかがチェックされます。この戻り値が 7 に等しいときはいつでも、サイコロの目は大きくなりすぎたので、1 の値にリセットされます。こうして、diceRoll 値の続き方は常に 1、2、3、4、5、6、1、2 というように続きます。
サイコロを振った後、プレイヤーは diceRoll の正方形へと前進します。サイコロの目が正方形の 25 を超えてプレイヤーを移動している可能性があり、その場合ゲームは終わっています。このシナリオに対処するために、コードは square が board 配列の count プロパティ未満であることをチェックします。square が有効な場合、現在の square 値に board[square] に格納された値が追加され、どれかの梯子やヘビを上下してプレイヤーを移動します。
そして現在の while ループの実行は終了し、ループの条件は、ループが再び実行されるべきかどうかをチェックします。プレーヤーが正方形 25 番に達するか超えた場合、ループの条件は false と評価され、ゲームは終了します。
ゲームの長さは、while ループの開始時には明らかでないので、while ループは、この場合適切です。その代わり、特定の条件が満たされるまで、ループが実行されます。
repeat-while ループとして知られている while ループの他の変種は、ループの条件を検討する 前に、最初にループブロックを一回実行します。その後、条件が false になるまでループを繰り返し続けます。
repeat-while ループの一般的な形式は次のとおりです。
ここで再び、while ループではなく、repeat-while ループとして書かれた 蛇と梯子 の例を挙げます。finalSquare、board、square および diceRoll の値は、while ループとまったく同じ方法で初期化されます。
ゲームのこのバージョンでは、ループ内の 最初 のアクションは梯子やヘビをチェックすることです。ボードでは梯子はまっすぐに正方形 25 にプレーヤーを送らないので、梯子を登って移動してもゲームに勝つことはできません。したがって、ループの最初のアクションで蛇や梯子をチェックするのは安全です。
ゲーム開始時、プレイヤーは "正方形ゼロ" にいます。board[0] は常に 0 に等しく、効果はありません。
コードが蛇や梯子をチェックした後、ダイスは振られ、プレーヤーは diceRoll の数だけ正方形を前方に移動されます。現在のループの実行はそして終了します。
ループの条件(while square < finalSquare)は以前と同じですが、今回は、ループを通る最初の実行の 終了 までそれは評価されません。repeat-while ループの構造は、前の例の、while ループよりも、このゲームに適しています。上記の repeat-while ループでは、square += board[square] は、square がまだボード上にある事をループの while 条件が確認した 直後 に実行されます。この動作は、前に説明したゲームの while ループのバージョンで見られる配列境界チェックの必要性を取り除きます。
一定の条件に基づいて、異なるコードの部分を実行するとこれはしばしば便利です。値が高すぎたり低すぎたりしたときメッセージを表示したい場合や、エラーが発生したときにコードの特別な部分を実行したい時があります。これを行うには、コードの一部を 条件付き にします。
Swift は、if 文と switch 文の、コードに条件分岐を追加する2つの方法を提供します。一般的には、いくつかのありうる結果のみが出る単純な条件を評価する if 文を使用して下さい。switch 文は、複数のありうる順列の、より複雑な条件に適していて、パターンマッチングが、実行するための適切なコード分岐を選択する時に便利です。
最も単純な形式では、if 文には、単一の if 条件があります。それは、その条件が true の場合にのみ一連の文を実行します。
上記の例では、温度が華氏 32 度(水の凍結点)以下かどうかをチェックします。その場合、メッセージが印刷されます。そうでない場合は、メッセージは印刷されず、コードの実行は、if 文の閉じ括弧以後を続けます。
if 文は、if の条件が false であるときの else 句 として知られる一連の代替文を提供します。これらの文は、else のキーワードで示されます。
これら2つの分岐のうち一つが常に実行されます。温度が華氏 40 度に上がっているので、もはやスカーフを着用するよう助言するほど寒くなく、したがって、else の分岐が代わりに引き起こされます。
追加の句を検討する場合は、複数の if 文を連鎖させることができます。
ここでは、追加の if 文は特に暖かい温度に対応するために追加されました。最後の else 句が残り、暖かすぎもせず寒すぎもしないすべての温度に対する応答を印刷します。
最後の else 句はしかし、任意であり、一連の条件が完全である必要がない場合は、除外することができます:
if 条件を引き起こすほど温度が低くなく、また else if 条件を引き起こすほど暖かくないため、メッセージは出力されません。
Swift では、値を設定するときに使用できる if の省略表記が提供されています。たとえば、以下のコードを考えてみましょう。
ここで、各分岐は、if 文の後に出力される、weatherAdvice 定数の値を設定します。
if 式として知られる代替構文を使用すると、このコードをより簡潔に記述することができます。
この if の式バージョンでは、各分岐に単一の値が含まれます。分岐の条件が true の場合、その分岐の値が、weatherAdvice の代入の if 内の式全体の値として使用されます。すべての if 分岐には、対応する else if 分岐または else 分岐があり、どの条件が true であるかに関係なく、分岐の 1 つが常に一致し、if 式が常に値を生成することが保証されます。
代入の構文は if 式の外側で始まるため、各分岐内で WeatherAdvice = を繰り返す必要はありません。代わりに、if 式の各分岐は、weatherAdvice の 3 つの可能な値のうちの 1 つを生成し、代入にはその値が使用されます。
if 式のすべての分岐には、同じ型の値が含まれている必要があります。Swift は各分岐の型を個別にチェックするため、一つ以上の型で使用できる nil のような値により、Swift が if 式の型を自動的に決定することができなくなります。代わりに、型を明示的に指定する必要があります。たとえば、以下のようになります。
上記のコードでは、if 式の 1 つの分岐には文字列値があり、もう 1 つの分岐には nil 値があります。nil 値は任意の optional 型の値として使用できるため、型注釈 で説明されているように、freezeWarning が optional の文字列であることを明示的に記述しなければなりません。
この型情報を提供する別の方法は、freezeWarning に明示的な型を提供する代わりに、nil に対して明示的な型を提供することです。
if 式は、エラーをスローするか、決して返さない FatalError(_:file:line:) のような関数を呼び出すことによって、予期せぬエラーに応答できます。例えば:
この例では、if 式は予測温度が 100° C (水の沸点) より高いかどうかをチェックします。これほど高温になると、if 式はテキストの概要を返す代わりに .boiling エラーをスローします。この if 式はエラーをスローする可能性がありますが、その前に try を記述しません。エラーの処理については、エラー処理 を参照してください。
上記の例に示すように、代入の右辺で if 式を使用するだけでなく、関数またはクロージャが返す値としてそれらを使用することもできます。
switch 文は、値を考慮し、いくつかの一致する可能性のあるパターンとそれを比較します。その後、成功裏に一致する最初のパターンに基づいて適切なコードのブロックを実行します。switch 文は、複数の潜在的な状態に対応するための if 文の代替手段を提供します。
その最も単純な形態では、switch 文は、同じ型の1つ以上の値に対して値を比較します。
すべての switch 文は、それぞれ case キーワードで始まる、複数の可能性のある case で構成されています。特定の値と比較することに加えて、Swift はそれぞれの case で、より複雑な一致パターンを指定するための方法をいくつか提供しています。これらのオプションは、この章の後の方で説明します。
if 文の本体と同様に、それぞれの case は、コード実行の別れた分岐です。switch 文は、どの分岐を選択すべきかを決定します。この手順は、検討されている値への 切り替え(switching) として知られています。
すべての switch 文は、網羅的 でなければなりません。つまり、型の全ての可能性のある値は switch の case のいずれか1つに一致しなければなりません。もしすべての可能性のある値に case を提供するのが適切でない場合は、明示的に対処されていないすべての値をカバーするために、デフォルトの case を定義できます。このデフォルトの case は、キーワード default で示され、常に最後に表示しなければなりません。
以下の例では、someCharacter と呼ばれる一つの小文字を考える switch 文を使用しています。
switch 文の最初の case は、英語のアルファベットの最初の文字 a に一致し、第二の case は、最後の文字の z に一致します。switch は、全てのアルファベット文字だけではなくすべての可能性のある文字の case を持たなければならないので、この switch 文は、a や z 以外の、すべての文字に一致するように default の case を使用します。この規定が、switch 文は網羅的であることを保証します。
if 文と同様に、switch 文にも式形式があります。
この例では、switch 式の各 case には、その case が anotherCharacter と一致する場合に使用されるメッセージの値が含まれています。switch は常に網羅的であるため、割り当てる値が常に存在します。
if 式と同様に、与えられた case に値を提供する代わりに、エラーをスローしたり、決して戻らない FatalError(_:file:line:) のような関数を呼び出したりできます。上記の例に示すように、switch 式は代入の右辺で、関数またはクロージャが返す値として使用できます。
C や Objective-C の switch 文とは対照的に、Swift の switch 文は、各 case の底部を通って、デフォルトで次のものへとは通って(fall through) 行きません。その代わりに、全体の switch 文は、明示的な break 文を必要とせずに、最初に一致した switch の case が完了するやいなや、その実行を終了します。これは switch 文を、C のそれより安全で、より使いやすくし、誤って複数の switch の case を実行する事を防ぎます。
各 case の本体は、少なくとも一つの実行可能文を含まなければなりません。最初の case が空であるため、以下のコードを書くのは有効ではありません。
C 言語での switch 文とは異なり、この switch 文は、"a" と "A" 両方ともに一致しません。むしろ、それは case "a": が実行可能な文を含んでいないというコンパイル時エラーを報告します。このアプローチは、一つの case から別の case への偶発的な fallthrough を回避し、かつその意図を明確にし、より安全なコードにします。
"a" と "A" の両方で単一の case に switch を一致するようにするには、値をコンマで区切って、複合した case に2つの値を組み合わせます。
読みやすくするために、複合した case も複数行に書くことができます。複合した case の詳細については、複合した case を参照してください。
switch の case の値は、それが範囲内に含まれるかどうかチェックできます。以下の例では、全てのサイズの数字について自然言語のカウントを提供するために、数字の範囲を使用しています。
上記の例では、approximateCount が、switch 文で評価されます。各 case は数や間隔とその値を比較します。 approximateCount の値が 12 と 100 の間に入るので、naturalCount は "dozens of" の値を割り当てられ、実行は switch 文の外に転送されます。
同じ switch 文で複数の値をテストするためにタプルを使用できます。タプルの各要素は、異なる値又は値の間隔に対してテストできます。代わりに、すべての可能な値と一致するように、ワイルドカードパターンとしても知られるアンダースコア(_)の文字を使ってください。
以下の例は、(x,y) の点をとり、(Int,Int) 型の単純なタプルで表され、例の後に表すグラフ上に分類します。
点が原点 (0,0) にあるかどうか switch 文が決定し、赤色の x 軸上か、緑色の y 軸上か、原点を中心にした青の 4×4 の青い箱の内側か、または箱の外側か、switch 文は決定します。
C 言語 とは異なり、Swift では、複数の switch の case が同じ値または複数の値と考えることを許可します。実際に、点 (0,0) は、この例の case の 4つ すべてに一致します。しかし、複数の一致が可能な場合には、最初に一致した case が常に使用されます。点 (0,0) は、最初に case (0,0) と一致するので、他のすべての一致する case は無視されます。
switch の case は、case の本体内で使用するための一時的な定数や変数に一致する値または複数の値を名付けられます。この動作は 値の結合 として知られ、値が case の本体内の一時的な定数や変数に"結合"されるためです。
以下の例は、(x,y)の点を取り、(Int,Int) 型のタプルとして表現され、以下のグラフの上に分類されます。
switch 文は、点が赤色の x 軸上にあるか、緑色の y 軸上にあるか、(どちらの軸上でもない)他の場所にあるかを決定します。
3 つの switch の case は一時的に anotherPoint から一つまたは両方のタプルの値をとるプレースホルダの定数 x と y を宣言します。最初の case では、case (let x,0) であり、0 の値を持つ y と一時的な定数 x に点の x 値を割り当てる任意の点に一致します。同様に、第二の case、case(0,let y) では、0 の値を持つ x と一時的な定数 y に点の y 値を割り当てる任意の点に一致します。
一時的な定数が宣言されると、それらは case のコードブロック内で使用できます。ここで、それらは点の分類を印刷する為に使用されています。
この switch 文は、default の case を持っていません。最後の case、case let(x、y) は、任意の値に一致する2つのプレースホルダ定数のタプルを宣言しています。anotherPoint は、常に 2 つの値のタプルであるため、この case は、すべての可能な残りの値と一致し、default の case は、switch 文が網羅するためには必要とされていません。
switch の case は、追加の条件をチェックするのに where 句を使用できます。
以下の例は、以下のグラフ上の点(x、y)を分類します:
点が緑色の対角線の where x == y 上か、紫色の対角線上の where x == -y か、またはどちらでもないかを、switch 文が決定します。
switch の3つの case は yetAnotherPoint から2つのタプル値を一時的にとり、プレースホルダ定数の x と y を宣言します。これらの定数は、動的フィルタを作成するために、where 句の一部として使用されています。 switch の case は、where 句の条件が、その値が true と評価された場合にのみ point の現在の値と一致します。
前の例のように、最後の case は、残りのすべての可能な値と一致し、これで default case は、switch 文を網羅するために必要とされません。
同じ本体を共有する複数の switch case は、case の後にいくつかのパターンを書き、それぞれのパターンの間にコンマを書く事で組み合わせることができます。パターンのいずれかが一致する場合、case は一致すると考えられます。リストが長い場合、パターンは複数行に書く事ができます。例えば:
switch 文の最初の case は、英語の5つすべての小文字の母音と一致します。同様に、第二の case は、すべての小文字の英語の子音と一致します。最後に、default の case は、他の文字と一致します。
また複合した case は、値の結合を含むこともできます。複合した case のすべてのパターンが値の結合の同じセットを含まなければならず、各々の結合は復合した case のすべてのパターンから同じ型の値を取得しなければなりません。これは復合した case のどの部分が一致したかによらず、case の本体のコードは常に結合した値にアクセスでき、値が常に同じ型を持っていることを保証します。
上記の case には、二つのパターンがあります:x 軸上の点に一致する (let distance,0) と、y 軸上の点と一致する (0,let distance) です。両方のパターンは、distance の結合を含んでおり、両方のパターンで distance は整数です–これは、case の本体内のコードは常に distance の値にアクセスできることを意味します。
制御転送文 は、コードが実行される順序を変更し、コードの一つの部分から別の部分へと、制御を転送します。Swift には5つの制御転送文があります。
continue, break, そして fallthrough 文は以下に説明します。return 文は、関数 で説明し、throw 文は throw する関数を使用したエラーの伝播 で説明します。
continue 文は、ループを通じて、次の反復の開始時に、何をしようとし再び開始しようとしているのを停止するよう、ループに伝えます。それは、完全にループを離れることなく、"私は現在のループの繰り返しを終わりました" と言う事です。
以下の例では、秘密のパズルの句を作るために小文字の文字列からすべての母音とスペースを削除します。
上記のコードでは、母音またはスペースと一致するたびに、continue キーワードを呼び出し、ループの現在の繰り返しを生じてすぐに終了して次の繰り返しの先頭にまっすぐ進みます。
break 文は、フロー制御文全体の実行をすぐに終了します。break 文は、switch 文やループ文の内部で使用することができ、そうでない case よりも、switch 文やループ文の実行を速く終了したいときに使用します。
ループ文の中で使用された場合、break はすぐにループの実行を終了し、ループの閉じ括弧 (})の後のコードに制御を移します。ループの現在の繰り返しから、それ以上のコードは実行されず、ループのさらなる繰り返しは開始されません。
switch 文の中で使用された場合、break はその switch 文の実行をすぐに終了し、switch 文の閉じ括弧 (})の後のコードに制御を移します。
この動作は、switch 文内の 1 つ以上の case に一致し無視する時に使用できます。Swift の switch 文は網羅的であり、空の case を許可していないので、あなたの意図を明示するために case に故意に一致し無視する必要がある場合があります。無視したい case の本体全体として break 文を書くことでこれを行います。その case が switch 文で一致している場合、case 内の break 文は、switch 文の実行を直ちに終了します。
以下の例は、Character の値で switch し、それが4つの言語のいずれかで数記号を表しているかを決定します。簡単のために、複数の値を、一つの switch の case でカバーしています。
この例では、numberSymbol が、ラテン語、アラビア語、中国語、またはタイ語の 1 から 4 までの数字のシンボルかどうかを決定します。一致する物が見つかると、switch 文の case の一つが、possibleIntegerValue と呼ばれる optional の Int? 変数を、適切な整数値に設定します。
switch 文がその実行を完了した後、例は、値が見つかったかどうかを判断するために、optional の結合を使用します。possibleIntegerValue 変数は、optional の型であるおかげで、nil の暗黙の初期値を持っており、optional の結合は possibleIntegerValue が、switch 文の最初の4つの case の一つにより実際の値に設定された場合にのみ成功します。
上記の例ではすべての可能な Character の値を列挙することは現実的ではないので、default の case が、一致しない全ての文字を処理します。この default の case は、アクションを全く実行する必要がないので、その本体として一つの break 文が書かれています。default の case が一致するやいなや、break 文は、switch 文の実行を終了し、コードの実行は、if let 文から継続されます。
Swift では、switch 文は各 case の底を通って、次の case に落ちては行きません。すなわち、全体の switch 文は最初に一致した case が完了するやいなや、その実行を完了します。これとは対照的に、C では、fallthrough を防ぐために全ての switch case の最後に明示的な break 文を挿入する必要があります。デフォルトの fallthrough を回避することは Swift の switch 文の方が C 言語の相当する部分よりはるかに簡潔かつ予測可能であり、したがって、それらは誤って複数の switch の case を実行する事を防ぐ事を意味します。
C 言語 スタイルの fallthrough の動作を必要とする場合は、fallthrough キーワードで、ケースバイケースの基本でこの動作を選ぶことができます。以下の例では、数字のテキスト記述を作成するのに fallthrough を使用しています。
この例では、description と呼ばれる新しい String 変数を宣言し、それに初期値を代入しています。関数はその後、switch 文を使用して integerToDescribe の値を考慮します。integerToDescribe の値が、リスト内の素数のいずれかである場合、関数は、数値が素数であることに注意させるため、description の後にテキストを追加します。その後、同様に、default の case に"落ちる"ために fallthrough キーワードを使用します。default の case は、説明(description)の後にいくつか余分なテキストを追加し、switch 文は終わります。
integerToDescribe の値が既知の素数のリストにない場合、それは第一の switch の case に全く一致しません。そこには他の特定の case はありませんので、 integerToDescribe は default の case に一致します。
switch 文が実行を終了した後は、数字の説明(description)が print(_:separator:terminator:) 関数を使用して印刷されます。この例では、数字 5 は正しく素数として識別されます。
Swift では、他のループや条件文の内側のループや条件文を、複雑な制御フロー構造を作成する為に入れ子にすることができます。しかし、ループや条件文の両方とも途中でその実行を終了する break 文を使用できます。したがって、あなたが終了すべき break 文が欲しいループや条件文を明示することが時には便利です。同様に、複数の入れ子にされたループがある場合も、continue 文が影響を与えるべきループがどれかを明示する事が便利です。
これらの目的を達成するためには、ループ文や条件文を 文のラベル でマークできます。条件文で使用すると、ラベル付きの文の実行を終了する break 文で文ラベルを使用できます。ループ文で使用すると、break 文や continue 文で文ラベルを使用でき、ラベル付きの文の実行を終了したり、継続したりできます。
ラベル付き文は、文の導入キーワードと同じ行に、ラベルを配置して示され、コロンが続きます。原則はすべてのループや switch 文と同じですが、ここでは、while ループでこの構文の例を挙げます。
以下の例では、break 文と continue 文を使用して、この章の初めで見た 蛇と梯子 ゲームの改造バージョンでラベル付きの while ループを使っています。今回は、ゲームは特別のルールがあります:
特定のサイコロを振って正方形の 25 を超えた場合には、正方形の 25 に着陸するために必要な正確な数を振るまで振り続けなければなりません。
ゲームボードは以前と同じです。
finalSquare、board、square、 および diceRoll の値は以前と同じように初期化されます。
ゲームのこのバージョンは、ゲームの論理を実装する while ループと switch 文を使用します。while ループには、gameloop と呼ばれる文のラベルがあり、それが蛇と梯子ゲームの主なゲームループであることを示します。
while ループの条件は、while square != finalSquare で、正方形 25 上に正確に着陸しなければならないことを反映しています。
サイコロは、各ループの最初に振られます。すぐにプレイヤーを移動するよりも、むしろループは移動の結果を考慮し、移動が許可されているかどうかを決定する為 switch 文を使用します。
上記の break 文が、gameLoop ラベルを使用しなかった場合、while 文ではなく、switch 文を抜け出すでしょう。gameLoop ラベルを使用すると、どの制御文を終了すべきかが明らかになります。
guard 文は、if 文のように、式のブール値に応じて文を実行します。guard 文が実行された後にはコードの条件が真でなければならないことを要求するように guard 文を使用して下さい。if 文とは異なり、guard 文は条件が真でない場合実行される、else 節内のコードである、else 節が常にあります。
guard 文の条件が満たされた場合、コードの実行は guard 文の閉じ括弧の後に続きます。条件の一部として、optuinal の結合を使用して値を代入されたすべての変数または定数は guard 文が表示された、コードブロックの残りで利用可能です。
その条件が満たされない場合、else 分岐内のコードが実行されます。その分枝は guard 文が表示されるコードブロックを終了するため制御を転送しなければなりません。それは、return,break,continue、または throw のような制御転送文でこれを行うことができ、あるいは fatalError(_:file:line:) のように返さない関数やメソッドを呼び出すことができます。
要件について、guard 文を使用すると、if 文で同じチェックをするのと比較すると、コードの可読性を向上します。これにより、通常実行されるコードを else ブロックで包みこまずに記述でき、違反した要件を処理するコードを要件の隣に保持できます。
あなたのコードの一部を実行するかどうか、または実行回数を制御できる if や while などの制御フロー構造とは異なり、コードの一部が実行される ときに 制御を defer (延期) します。defer ブロックを使用して、後であなたのプログラムが現在のスコープの終わりに到達したときに実行されるコードを作成します。 例えば:
上記の例では、if 文の本体を終了する前に、defer ブロック内のコードが実行されます。まず、if 文内のコードが実行され、score が 5 つずつ増加します。次に、if 文のスコープを終了する前に、遅延したコードが実行され、score が出力されます。
プログラムがそのスコープをどのように終了するかに関係なく、defer 内のコードは常に実行されます。これには、関数の早期終了、for ループの抜け出し、エラーの throw などのコードが含まれます。この動作により、defer は、手動でのメモリの割り当てと解放、低レベルのファイル記述子のオープンとクローズ、データベースでの処理の開始と終了など、ペアとなるアクションの発生を保証する必要がある操作に役立ちます。これは、両方のアクションを隣に記述できるためです。たとえば、以下のコードは、コードの塊内で 100 を加算および減算することにより、スコアに一時的なボーナスを与えます。
同じスコープ内に複数の defer ブロックを作成した場合、最初に指定した defer ブロックが最後に実行されます。
例えば、実行時エラーやクラッシュが原因でプログラムの実行が停止した場合、遅延したコードは実行されません。ただし、遅延したコードはエラーが throw された後に実行されます。エラー処理での defer の使用については、クリーンアップ アクションの指定 を参照してください。
Swift には API の利用可能性を確認するためのサポートが組み込まれていますが、与えられた展開ターゲットでは使用できない API を誤って使用しないことをそれは保証します。
コンパイラは、コード内で使用される全ての API が、プロジェクトで指定された展開ターゲット上で使用可能であることを確認するために SDK の利用情報を使用します。利用できない API を使用しようとした時、Swift は、コンパイル時にエラーを報告します。
使用したい API が実行時に利用可能かどうかに応じて、コードのブロックを条件付きで実行する、if または guard 文で 利用可能性の条件 を使用して下さい。コードのそのブロック内の API が利用可能であることを確認したときにコンパイラは利用可能の条件からの情報を使用します。
上記の利用可能性の条件は、iOS 内のそれを指定し、if 文の本体は iOS 10 以降のみで、macOS では macOS 10.12 以降でのみ実行します。最後の引数、* は、他の任意のプラットフォーム上で必要で指定しており、if の本体はあなたのターゲットによって指定された最小展開ターゲット上で実行します。
その一般的な形式では、利用可能性の条件は、プラットフォームの名前とバージョンのリストを取ります。iOS、macOS、watchOS や tvOS のようなプラットフォームの名前を使用しますが、その完全なリストは、宣言の属性 を参照してください。iOS 8 や macOS 10.10 のようにメジャーなバージョン番号を指定するのに加え、iOS 11.2.6 や macOS 10.13.3 のようなマイナーなバージョン番号を指定できます。
guard 文で利用可能性条件を使用すると、そのコードブロックの残りのコードに使用される利用可能情報が洗練されます。
上記の例では、ColorPreference 構造体には macOS 10.12 以降が必要です。chooseBestColor( ) 関数は、利用可能性の guard で始まります。プラットフォームのバージョンが古すぎて ColorPreference を使用できない場合は、常に利用可能な動作になります。guard 文の後、macOS 10.12 以降を必要とする API を使用できます。
#available に加えて、Swift は利用不可条件を使用した反対のチェックもサポートしています。たとえば、以下の 2 つのチェックは同じことを行います。
#unavailable 形式を使用すると、チェックにフォールバックコードのみが含まれている場合に、コードがより読みやすくなります。