Swift 5.8 日本語化計画 : Swift 5.8


フロー制御


分岐、ループ、および早期終了を含む構造コード。


Swift は 様々なフロー制御文を提供しています。これらはタスクを複数回実行できる while ループを含み、 if、guardswitch 文は、一定の条件に基づいてコードの異なる分岐を実行し、そして breakcontinue のような文は、コード内の別のポイントに実行のフローを転送します。


Swift は for-in ループも提供し、それによって簡単に、配列、dictionary、範囲、文字列、および他のシーケンスを反復処理できます。


Swift の switch 文も、対応する多くの C に似た言語よりもとても強力と考えられます。Case は、間隔の一致、タプル、特定の型へのキャストなどを含む、さまざまなパターンに一致する事ができます。switch のケース内の一致した値は、case の本体内で使用するための一時的な定数または変数に結合することができ、複雑な一致条件は、それぞれの case について where 句で表すことができます。


For-In ループ


配列内の項目、数字の範囲、または文字列内の文字のような、シーケンスを反復処理するため for-in ループを使用して下さい。


以下の例では for-in ループを使用して、配列内の項目を反復処理します。


  1. let names = ["Anna", "Alex", "Brian", "Jack"]
  2. for name in names {
  3. print("Hello, \(name)!")
  4. }
  5. // Hello, Anna!
  6. // Hello, Alex!
  7. // Hello, Brian!
  8. // Hello, Jack!


また、dictionary を繰り返し処理して、そのキー値のペアにアクセスすることもできます。dictionary が反復処理されるときに dictionary の各項目は (key, value) タプルとして返され、for-in ループの本体内で使用する明示的に名前が付けられた定数として (key, value) タプルのメンバーを分解できます。以下のコード例では、dictionary のキーは animalName という定数に分解され、dictionary の値は legCount という定数に分解されます。


  1. let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
  2. for (animalName, legCount) in numberOfLegs {
  3. print("\(animalName)s have \(legCount) legs")
  4. }
  5. // cats have 4 legs
  6. // ants have 6 legs
  7. // spiders have 8 legs


Dictionary の内容は本質的に順序付けされておらず、それらを反復処理しても、それらが取得される順序は保証されません。特に、Dictionary に項目を挿入する順序は、それらが反復処理される順序を定義しません。配列と dictionary の詳細については、コレクション型 を参照してください。


数値範囲で for-in ループを使用することもできます。以下の例では、5倍の表の最初のいくつかのエントリを印刷します。


  1. for index in 1...5 {
  2. print("\(index) times 5 is \(index * 5)")
  3. }
  4. // 1 times 5 is 5
  5. // 2 times 5 is 10
  6. // 3 times 5 is 15
  7. // 4 times 5 is 20
  8. // 5 times 5 is 25


閉鎖範囲演算子(...)の使用によって示される、反復処理されるシーケンスは、1 から 5 の数値の範囲です。index の値は、範囲内の最初の数(1)に設定され、ループ内の文が実行されます。この場合、ループは、index の現在値の5倍の表からエントリを印刷する、一つの文だけを含んでいます。文が実行された後、index の値は範囲の 2 番目の値(2)を含むように更新され、print(_:separator:terminator:) 関数が再び呼び出されます。範囲の最後に到達するまで、このプロセスが続きます。


上記の例では、index は、その値がそれぞれのループの繰り返しの開始時に自動的に設定される定数です。このように、index は使用される前に宣言する必要はありません。これは、let 宣言キーワードを必要とせずに、ループ宣言内でそれを含むことにより、簡単に暗黙的に宣言されます。


シーケンスからの各々の値を必要としない場合は、変数名の代わりにアンダースコアを使用して、値を無視できます。


  1. let base = 3
  2. let power = 10
  3. var answer = 1
  4. for _ in 1...power {
  5. answer *= base
  6. }
  7. print("\(base) to the power of \(power) is \(answer)")
  8. // prints "3 to the power of 10 is 59049"


上記の例では、1つの数値に別の数を累乗した値を計算(この場合は 310 乗)します。これは、1(すなわち 30 乗) から始まり、10回、1 から始まり 10 で終わる閉鎖範囲を使用して 3 を乗算します。この計算では、個々のカウンタ値は各々の回のループ中には必要はなく、コードは単にループを正しい回数実行する必要があります。アンダースコア文字 (_)はループ変数の代わりに使用され、個々の値は無視され、ループの各繰り返し中に現在値へのアクセスを提供しません。


状況によっては、両方の端を含む閉じた範囲を使用したくない場合もあります。時計盤上に 1 分ごとに目盛りを描くことを考えてください。0 分から開始して 60 目盛りを描きたいとします。下限を含めるが上限は含まない半開放範囲演算子(..<) を使用して下さい。範囲の詳細については、範囲演算子 を参照してください。


  1. let minutes = 60
  2. for tickMark in 0..<minutes {
  3. // render the tick mark each minute (60 times)
  4. }


一部のユーザーは、彼らの UI で目盛りの数を減らしたいと思うかも知れません。代わりに 5 分ごとに 1 つのマークを好むかも知れません。stride(from:to:by:) 関数を使用して、不要なマークをスキップしましょう。


  1. let minuteInterval = 5
  2. for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
  3. // render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
  4. }


stride(from:through:by:) を代わりに使用すると、閉じた範囲も使用できます。


  1. let hours = 12
  2. let hourInterval = 3
  3. for tickMark in stride(from: 3, through: hours, by: hourInterval) {
  4. // render the tick mark every 3 hours (3, 6, 9, 12)
  5. }


上記の例では、for-in ループを使用して、範囲、配列、辞書、および文字列を反復処理しています。ただし、この構文を使用して、独自のクラスやコレクション型を含む 任意の コレクションを反復処理できますが、それらの型が Sequence プロトコルに準拠している場合に限ります。


While ループ


while ループは条件が false になるまで一連の文を実行します。これらの種類のループは、最初の繰り返しが始まる前に繰り返しの回数が知られていないときに一番よく使用されます。Swift は、2種類の while ループを提供しています。


While


while ループは、単一の条件を評価することによって始まります。条件が true の場合、条件が false になるまで、一連の文が繰り返されます。


while ループの一般的な形式は以下のとおりです。


この例では、蛇と梯子 (雨どいと梯子 としても知られています) の簡単なゲームを遊びます:




このゲームのルールは以下のとおりです:


このゲームボードは、Int 値の配列によって表されます。そのサイズは、この例の後の方では勝利条件をチェックすることにも使いますが、配列を初期化するために使用される finalSquare という定数に基づいています。プレイヤーはボードを "ゼロ番目の正方形" で開始するので、ボードは 25個でなく、26個のゼロの Int 値で初期化されます:



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


その後、いくつかの正方形は、ヘビとはしごの、より特殊な値に設定されます。梯子の下のある正方形には、ボードを上に移動するように正の数を持たせ、ヘビの頭がある正方形には、ボードを下に移動するように負の数を持たせます:


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


正方形 3 は、正方形 11 まで上に移動する、梯子の下を含んでいます。これを表すために、board[03]+08 に等しく、整数値 8 (311 の差)と同等です。値と文が合うように、単項プラス演算子(+i)は単項マイナス演算子(-i)とバランスを取るため、また 10 より少ない数字は、ゼロで埋められます。(どちらの書式のテクニックとも、厳密には必要でありませんが、それらにより、コードがすっきりします。)


  1. var square = 0
  2. var diceRoll = 0
  3. while square < finalSquare {
  4. // roll the dice
  5. diceRoll += 1
  6. if diceRoll == 7 { diceRoll = 1 }
  7. // move by the rolled amount
  8. square += diceRoll
  9. if square < board.count {
  10. // if we're still on the board, move up or down for a snake or a ladder
  11. square += board[square]
  12. }
  13. }
  14. print("Game over!")


上記の例では、サイコロを振るために、非常に簡単なアプローチを使用しています。乱数発生の代わりに、 0diceRoll 値で始まります。while ループを通るごとに、diceRoll は、ひとつ増分された後、大きくなりすぎていないかどうかがチェックされます。この戻り値が 7 に等しいときはいつでも、サイコロは大きくなりすぎたので、1 の値にリセットされます。こうして、diceRoll 値の続き方は常に 1、2、3、4、5、6、1、2 というように続きます。


サイコロを振った後、プレイヤーは diceRoll の正方形へと前進します。サイコロの目が正方形の 25 を超えてプレイヤーを移動している可能性があり、その場合ゲームは終わっています。このシナリオに対処するために、コードは squareboard 配列の count プロパティ未満であることをチェックします。square が有効な場合、現在の square 値が board[square] に格納された値に追加され、どれかのはしごやヘビを上下してプレイヤーを移動します。


注意: このチェックが行われないと、board[square] は、board 配列の範囲の外の値にアクセスしようとするかも知れず、実行時エラーを引き起こすでしょう。


そして現在の while ループの実行は終了し、ループの条件は、ループが再び実行されるべきかどうかをチェックします。プレーヤーが正方形 25 番に達するか超えた場合、ループの条件は false と評価され、ゲームは終了します。


ゲームの長さは、while ループの開始時には明らかでないので、while ループは、この場合適切です。その代わり、特定の条件が満たされるまで、ループが実行されます。



Repeat-While


repeat-while ループとして知られている while ループの他の変種は、ループの条件を検討する 前に、最初にループブロックを一回実行します。その後、条件が false になるまでループを繰り返し続けます。


注意: Swift における repeat-while ループは、他の言語の do-while ループに似ています。


repeat-while ループの一般的な形式は次のとおりです。


ここで再び、while ループではなく、repeat-while ループとして書かれた 蛇と梯子 の例を挙げます。finalSquare、board、square および diceRoll の値は、while ループとまったく同じ方法で初期化されます。


  1. let finalSquare = 25
  2. var board = [Int](repeating: 0, count: finalSquare + 1)
  3. board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
  4. board[14] = -10; board [19] = - 11; board[22] = - 02; board[24] = - 08
  5. var square = 0
  6. var diceRoll = 0

ゲームのこのバージョンでは、ループ内の 最初 のアクションは梯子やヘビをチェックすることです。ボードでは梯子はまっすぐに正方形 25 にプレーヤーを送らないので、梯子を登って移動してもゲームに勝つことはできません。したがって、ループの最初のアクションで蛇や梯子をチェックするのは安全です。


ゲーム開始時、プレイヤーは "正方形ゼロ" にいます。board[0] は常に 0 に等しく、効果はありません。


  1. repeat {
  2. // move up or down for a snake or ladder
  3. square += board[square]
  4. // roll the dice
  5. diceRoll += 1
  6. if diceRoll == 7 { diceRoll = 1 }
  7. // move by the rolled amount
  8. square += diceRoll
  9. } while square < finalSquare
  10. print("Game over!")


コードが蛇や梯子をチェックした後、ダイスは振られ、プレーヤーは diceRoll の数だけ正方形を前方に移動されます。現在のループの実行はそして終了します。


ループの条件(while square < finalSquare)は以前と同じですが、今回は、ループを通る最初の実行の 終了 までそれは評価されません。repeat-while ループの構造は、前の例の、while ループよりも、このゲームに適しています。上記の repeat-while ループでは、square += board[square] は、square がまだボード上にある事をループの while 条件が確認した 直後 に実行されます。この動作は、前に説明したゲームの while ループのバージョンで見られる配列境界チェックの必要性を取り除きます。



条件文


一定の条件に基づいて、異なるコードの部分を実行するとこれはしばしば便利です。値が高すぎたり低すぎたりしたときメッセージを表示したい場合や、エラーが発生したときにコードの特別な部分を実行したい時があります。これを行うには、コードの一部を 条件付き にします。


Swift は、if 文と switch 文の、コードに条件分岐を追加する2つの方法を提供します。一般的には、いくつかのありうる結果のみが出る単純な条件を評価する if 文を使用して下さい。switch 文は、複数のありうる順列の、より複雑な条件に適していて、パターンマッチングが、実行するための適切なコード分岐を選択する時に便利です。



if 文


最も単純な形式では、if 文には、単一の if 条件があります。それは、その条件が true の場合にのみ一連の文を実行します。


  1. var temperatureInFahrenheit = 30
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. }
  5. // prints "It's very cold. Consider wearing a scarf."


上記の例では、温度が華氏 32 度(水の凍結点)以下かをチェックします。その場合、メッセージが印刷されます。そうでない場合は、メッセージは印刷されず、コードの実行は、if 文の閉じ括弧以後を続けます。


if 文は、if の条件が false であるときの else 句 として知られる一連の代替文を提供します。これらの文は、else のキーワードで示されます。


  1. temperatureInFahrenheit = 40
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. } else {
  5. print("It's not that cold. Wear a t-shirt.")
  6. }
  7. // prints "It's not that cold. Wear a t-shirt."


これら2つの分岐のうち一つが常に実行されます。温度が華氏 40 度に上がっているので、もはやスカーフを着用するよう助言するほど寒くなく、したがって、else の分岐が代わりに引き起こされます。


追加の句を検討する場合は、複数の if 文を連鎖させることができます。


  1. temperatureInFahrenheit = 90
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. } else if temperatureInFahrenheit >= 86 {
  5. print("It's really warm. Don't forget to wear sunscreen.")
  6. } else {
  7. print("It's not that cold. Wear a t-shirt.")
  8. }
  9. // prints "It's really warm. Don't forget to wear sunscreen."


ここでは、追加の if 文は特に暖かい温度に対応するために追加されました。最後の else 句が残り、暖かすぎもせず寒すぎもしないすべての温度に対する応答を印刷します。


最後の else 句はしかし、任意であり、一連の条件が完全である必要がない場合は、除外することができます:


  1. temperatureInFahrenheit = 72
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. } else if temperatureInFahrenheit >= 86 {
  5. print("It's really warm. Don't forget to wear sunscreen.")
  6. }


温度は暖かすぎもせず寒すぎもせず、ifelse if の条件を引き起こさず、メッセージは印刷されません。



Switch


switch 文は、値を考慮し、いくつかの一致する可能性のあるパターンとそれを比較します。その後、成功裏に一致する最初のパターンに基づいて適切なコードのブロックを実行します。switch 文は、複数の潜在的な状態に対応するための if 文の代替手段を提供します。


その最も単純な形態では、switch 文は、同じ型の1つ以上の値に対して値を比較します。


すべての switch 文は、それぞれ case キーワードで始まる、複数の可能性のある case で構成されています。特定の値と比較することに加えて、Swift はそれぞれの case で、より複雑な一致パターンを指定するための方法をいくつか提供しています。これらのオプションは、この章の後の方で説明します。


if 文の本体と同様に、それぞれの case は、コード実行の別れた分岐です。switch 文は、どの分岐を選択すべきかを決定します。この手順は、検討されている値への 切り替え(switching) として知られています。


すべての switch 文は、網羅的 でなければなりません。つまり、型の全ての可能性のある値は switch の case のいずれか1つに一致しなければなりません。もしすべての可能性のある値に case を提供するのが適切でない場合は、明示的に対処されていないすべての値をカバーするために、デフォルトの case を定義できます。このデフォルトの case は、キーワード default で示され、常に最後に表示しなければなりません。


以下の例では、someCharacter と呼ばれる一つの小文字を考える switch 文を使用しています。


  1. let someCharacter: Character = "z"
  2. switch someCharacter {
  3. case "a":
  4. print("The first letter of the alphabet")
  5. case "z":
  6. print("The last letter of the alphabet")
  7. default:
  8. print("Some other character")
  9. }
  10. // Prints "The last letter of the alphabet"


switch 文の最初の case は、英語のアルファベットの最初の文字 a に一致し、第二の case は、最後の文字の z に一致します。switch は、全てのアルファベット文字だけではなくすべての可能性のある文字の case を持たなければならないので、この switch 文は、az 以外の、すべての文字に一致するように default の case を使用します。この規定が、switch 文は網羅的であることを保証します。



暗黙の Fallthrough はなし


C や Objective-C の switch 文とは対照的に、Swift の switch 文は、各 case の底部を通って、デフォルトで次のものへとは通って(fall through) 行きません。その代わりに、全体の switch 文は、明示的な break 文を必要とせずに、最初に一致した switch の case が完了するやいなや、その実行を終了します。これは switch 文を、C のそれより安全で、より使いやすくし、誤って複数の switch の case を実行する事を防ぎます。



注意: break は Swift に必須ではありませんが、特定の case に一致して無視するように、break 文を使用でき、あるいは、その case が実行を完了する前に一致した case から break するために使って下さい。詳細については、Switch 文内の Break を参照してください。


各 case の本体は、少なくとも一つの実行可能文を含まなければなりません。最初の case が空であるため、以下のコードを書くのは有効ではありません。


  1. let anotherCharacter: Character = "a"
  2. switch anotherCharacter {
  3. case "a": // Invalid, the case has an empty body
  4. case "A":
  5. print("The letter A")
  6. default:
  7. print("Not the letter A")
  8. }
  9. // this will report a compile-time error


C 言語での switch 文とは異なり、この switch 文は、"a""A" 両方ともに一致しません。むしろ、それは case "a": が実行可能な文を含んでいないというコンパイル時エラーを報告します。このアプローチは、一つの case から別の case への偶発的な fallthrough を回避し、かつその意図を明確にし、より安全なコードにします。


"a""A" の両方に単一の case に switch を一致するようにするには、値をコンマで区切って、複合した case に2つの値を組み合わせます。


  1. let anotherCharacter: Character = "a"
  2. switch anotherCharacter {
  3. case "a", "A":
  4. print("The letter A")
  5. default:
  6. print("Not the letter A")
  7. }
  8. // Prints "The letter A"

読みやすくするために、複合した case も複数行に書くことができます。複合した case の詳細については、複合した case を参照してください。


注意: Fallthrough で説明したように、特定の switch case の最後で明示的に fallthrough するには、fallthrough キーワードを使用してください。


範囲の一致


switch の case の値は、それが範囲内に含まれるかどうかチェックできます。この例では、全てのサイズの数字について自然言語のカウントを提供するために、数字の範囲を使用しています。


  1. let approximateCount = 62
  2. let countedThings = "moon orbiting Saturn"
  3. var naturalCount: String
  4. switch approximateCount {
  5. case 0:
  6. naturalCount = "no"
  7. case 1..<5:
  8. naturalCount = "a few"
  9. case 5..<12:
  10. naturalCount = "several"
  11. case 12..<100:
  12. naturalCount = "dozens of"
  13. case 100..<1000:
  14. naturalCount = "hundreds of"
  15. default:
  16. naturalCount = "many"
  17. }
  18. print("There are \(naturalCount) \(countedThings).")
  19. // prints "There are dozens of moons orbiting Saturn."

上記の例では、approximateCount が、switch 文で評価されます。各 case は数や間隔とその値を比較します。 approximateCount の値が 12 と 100 の間に入るので、naturalCount"dozens of" の値を割り当てられ、実行は switch 文の外に転送されます。


タプル(Tuples)


同じ switch 文で複数の値をテストするためにタプルを使用できます。タプルの各要素は、異なる値又は値の間隔に対してテストできます。代わりに、すべての可能な値と一致するように、ワイルドカードパターンとしても知られるアンダースコア(_)の文字を使ってください。


以下の例は、(x,y)の点をとり、(Int,Int) 型の単純なタプルで表し、例の後に表すグラフ上に分類します。


  1. let somePoint = (1, 1)
  2. switch somePoint {
  3. case (0, 0):
  4. print("\(somePoint) is at the origin")
  5. case (_, 0):
  6. print("\(somePoint) is on the x-axis")
  7. case (0, _):
  8. print("\(somePoint) is on the y-axis")
  9. case (-2...2, -2...2):
  10. print("\(somePoint) is inside the box")
  11. default:
  12. print("\(somePoint) is outside of the box")
  13. }
  14. // prints "(1, 1) is inside the box"




点が原点 (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) 型のタプルとして表現され、以下のグラフの上に分類されます。


  1. let anotherPoint = (2, 0)
  2. switch anotherPoint {
  3. case (let x, 0):
  4. print("on the x-axis with an x value of \(x)")
  5. case (0, let y):
  6. print("on the y-axis with a y value of \(y)")
  7. case let (x, y):
  8. print("somewhere else at (\(x), \(y))")
  9. }
  10. // prints "on the x-axis with an x value of 2"




switch 文は、点が赤色の x 軸上にあるか、緑色の y 軸上にあるか、(どちらの軸上でもない)他の場所にあるかを決定します。


3 つの switch の case は一時的に anotherPoint から一つまたは両方のタプルの値をとるプレースホルダの定数 xy を宣言します。最初の 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 文が網羅するためには必要とされていません。


Where


switch の case は、追加の条件をチェックするのに where 句を使用できます。


以下の例は、以下のグラフ上の点(x、y)を分類します:


  1. let yetAnotherPoint = (1, -1)
  2. switch yetAnotherPoint {
  3. case let (x, y) where x == y:
  4. print("(\(x), \(y)) is on the line x == y")
  5. case let (x, y) where x == -y:
  6. print("(\(x), \(y)) is on the line x == -y")
  7. case let (x, y):
  8. print("(\(x), \(y)) is just some arbitrary point")
  9. }
  10. // prints "(1, -1) is on the line x == -y"




点が緑色の対角線の where x == y 上か、紫色の対角線上の where x == -y か、またはどちらでもないかを、switch 文が決定します。


switch の3つの case は yetAnotherPoint から2つのタプル値を一時的にとり、プレースホルダ定数の xy を宣言します。これらの定数は、動的フィルタを作成するために、where 句の一部として使用されています。 switch の case は、where 句の条件が、その値が true と評価された場合にのみ point の現在の値と一致します。


前の例のように、最後の case は、残りのすべての可能な値と一致し、これで default case は、switch 文を網羅するために必要とされません。



複合した case


同じ本体を共有する複数の switch case は、case の後にいくつかのパターンを書き、それぞれのパターンの間にコンマを書く事で組み合わせることができます。パターンのいずれかが一致する場合、case は一致すると考えられます。リストが長い場合、パターンは複数行に書く事ができます。例えば:


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


switch 文の最初の case は、英語の5つすべての小文字の母音と一致します。同様に、第二の case は、すべての小文字の英語の子音と一致します。最後に、default の case は、他の文字と一致します。


また複合した case は、値の結合を含むこともできます。複合した case のすべてのパターンが値の結合の同じセットを含まなければならず、各々の結合は復合した case のすべてのパターンから同じ型の値を取得しなければなりません。これは復合した case のどの部分が一致したかによらず、case の本体のコードは常に結合した値にアクセスでき、値が常に同じ型を持っていることを保証します。


  1. let stillAnotherPoint = (9, 0)
  2. switch stillAnotherPoint {
  3. case (let distance, 0), (0, let distance):
  4. print("On an axis, \(distance) from the origin")
  5. default:
  6. print("Not on an axis")
  7. }
  8. // Prints "On an axis, 9 from the origin"

上記の case には、二つのパターンがあります:x 軸上の点に一致する (let distance,0) と、y 軸上の点と一致する (0,let distance) です。両方のパターンは、distance の結合を含んでおり、両方のパターンで distance は整数です–これは、case の本体内のコードは常に distance の値にアクセスできることを意味します。


制御転送文


制御転送文 は、コードが実行される順序を変更し、一つのコードの部分から別の部分へと、制御を転送します。Swift には5つの制御転送文があります。


continue, break, そして fallthrough 文は以下に説明します。return 文は、関数 で説明し、throw 文は throw 関数を使用したエラーの伝播 で説明します。



Continue


continue 文は、ループを通じて、次の反復の開始時に、何をしようとし再び開始しようとしているのを停止するよう、ループに伝えます。それは、完全にループを離れることなく、"私は現在のループの繰り返しを終わりました" と言う事です。


以下の例では、秘密のパズルの句を作るために小文字の文字列からすべての母音とスペースを削除します。


  1. let puzzleInput = "great minds think alike"
  2. var puzzleOutput = ""
  3. let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
  4. for character in puzzleInput {
  5. if charactersToRemove.contains(character) {
  6. continue
  7. } else {
  8. puzzleOutput.append(character)
  9. }
  10. }
  11. print(puzzleOutput)
  12. // Prints "grtmndsthnklk"


上記のコードでは、母音またはスペースと一致するたびに、continue キーワードを呼び出し、ループの現在の繰り返しを生じてすぐに終了して次の繰り返しの先頭にまっすぐ進みます。



Break


break 文は、フロー制御文全体の実行をすぐに終了します。break 文は、switch 文やループ文の内部で使用することができ、そうでない case よりも、switch 文やループ文の実行を速く終了したいときに使用します。


ループ文内の Break


ループ文の中で使用された場合、break はすぐにループの実行を終了し、ループの閉じ括弧 (})の後のコードに制御を移します。ループの現在の繰り返しから、それ以上のコードは実行されず、ループのさらなる繰り返しは開始されません。



Switch 文内の Break


switch 文の中で使用された場合、break はその switch の実行をすぐに終了し、switch 文の閉じ括弧 (})の後のコードに制御を移します。


この動作は、switch 文内の 1 つ以上の case に一致し無視する時に使用できます。Swift の switch 文は網羅的であり、空の case を許可していないので、意図を明示するために case に故意に一致し無視する必要がある場合があります。無視したい case の本体全体として break 文を書くことでこれを行います。その case が switch 文で一致している場合、case 内の break 文は、switch 文の実行を直ちに終了します。



注意: コメントのみを含む switch の case は、コンパイル時にエラーとして報告されます。コメントは文ではなく、switch の case が無視されることはありません。switch の case を無視するには break 文を常に使用して下さい。


以下の例は、Character の値で switch し、それが4つの言語のいずれかで数記号を表しているかを決定します。簡単のために、複数の値を、一つの switch の case でカバーしています。


  1. let numberSymbol: Character = "三" // Chinese symbol for the number 3
  2. var possibleIntegerValue: Int?
  3. switch numberSymbol {
  4. case "1", "١", "一", "๑":
  5. possibleIntegerValue = 1
  6. case "2", "٢", "二", "๒":
  7. possibleIntegerValue = 2
  8. case "3", "٣", "三", "๓":
  9. possibleIntegerValue = 3
  10. case "4", "٤", "四", "๔":
  11. possibleIntegerValue = 4
  12. default:
  13. break
  14. }
  15. if let integerValue = possibleIntegerValue {
  16. print("The integer value of \(numberSymbol) is \(integerValue).")
  17. } else {
  18. print("An integer value could not be found for \(numberSymbol).")
  19. }
  20. // prints "The integer value of 三 is 3."


この例では、numberSymbol が、ラテン語、アラビア語、中国語、またはタイ語の 1 から 4 までの数字のシンボルかどうかを決定します。一致する物が見つかると、switch 文の case の一つが、optional の 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 文から継続されます。



Fallthrough


Swift では、switch 文は各 case の底を通って、次の case に落ちては行きません。すなわち、全体の switch 文は最初に一致した case が完了するやいなや、その実行を完了します。これとは対照的に、C では、fallthrough を防ぐために全ての switch case の最後に明示的な break 文を挿入する必要があります。デフォルトの fallthrough を回避することは Swift の switch 文の方が C 言語の相当する部分よりはるかに簡潔かつ予測可能であり、したがって、それらは誤って複数の switch の case を実行する事を防ぐ事を意味します。


C 言語 スタイルの fallthrough の動作を必要とする場合は、fallthrough キーワードで、ケースバイケースの基本でこの動作を選ぶことができます。以下の例では、数字のテキスト記述を作成するのに fallthrough を使用しています。


  1. let integerToDescribe = 5
  2. var description = "The number \(integerToDescribe) is"
  3. switch integerToDescribe {
  4. case 2, 3, 5, 7, 11, 13, 17, 19:
  5. description += " a prime number, and also"
  6. fallthrough
  7. default:
  8. description += " an integer."
  9. }
  10. print(description)
  11. // prints "The number 5 is a prime number, and also an integer."


この例では、description と呼ばれる新しい String 変数を宣言し、それに初期値を代入しています。関数はその後、switch 文を使用して integerToDescribe の値を考慮します。integerToDescribe の値が、リスト内の素数のいずれかである場合、関数は、数値が素数であることに注意させるため、description の後にテキストを追加します。その後、同様に、default の case に"落ちる"ために fallthrough キーワードを使用します。default の case は、説明(description)の後にいくつか余分なテキストを追加し、switch 文は終わります。


integerToDescribe の値が既知の素数のリストにない場合、それは第一の switch の case に全く一致しません。そこには他の特定の case はありませんので、 integerToDescribedefault の case に一致します。


switch 文が実行を終了した後は、数字の説明(description)が print(_:separator:terminator:) 関数を使用して印刷されます。この例では、数字 5 は正しく素数として識別されます。



注意: fallthrough キーワードは、その実行が陥る switch case の条件をチェックしません。fallthrough キーワードは単に、C の標準の switch 文の動作のように、コードの実行を次の case(または default の case)のブロック内の文に直接移動します。


ラベル付きの文


Swift では、他のループや条件文の内側のループや条件文を、複雑な制御フロー構造を作成する為に入れ子にすることができます。しかし、ループや条件文の両方とも途中でその実行を終了する break 文を使用できます。したがって、あなたが終了すべき break 文が欲しいループや条件文を明示することが時には便利です。同様に、複数の入れ子にされたループがある場合も、continue 文が影響を与えるべきループがどれかを明示する事が便利です。


これらの目的を達成するためには、ループ文や条件文を 文のラベル でマークできます。条件文で使用すると、ラベル付きの文の実行を終了する break 文で文ラベルを使用できます。ループ文で使用すると、break 文や continue 文で文ラベルを使用でき、ラベル付きの文の実行を終了したり、継続したりできます。


ラベル付き文は、文の導入キーワードと同じ行に、ラベルを配置して示され、コロンが続きます。原則はすべてのループや switch 文と同じですが、ここでは、while ループでこの構文の例を挙げます。


以下の例では、break 文と continue 文を使用して、この章の初めで見た 蛇と梯子 ゲームの改造バージョンでラベル付きの while ループを使っています。今回は、ゲームは特別のルールがあります:


特定のサイコロを振って正方形の 25 を超えた場合には、正方形の 25 に着陸するために必要な正確な数を振るまで振り続けなければなりません。


ゲームボードは以前と同じです。





finalSquare、board、square、 および diceRoll の値は以前と同じように初期化されます。


  1. let finalSquare = 25
  2. var board = [Int](repeating: 0, count: finalSquare + 1)
  3. board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
  4. board[14] = -10; board[19] = - 11; board[22] = -02; board[24] = -08
  5. var square = 0
  6. var diceRoll = 0


ゲームのこのバージョンは、ゲームの論理を実装する while ループと switch 文を使用します。while ループには、gameloop と呼ばれる文のラベルがあり、それが蛇と梯子ゲームの主なゲームループであることを示します。


while ループの条件は、while square != finalSquare で、正方形 25 上に正確に着陸しなければならないことを反映しています。


  1. gameLoop: while square != finalSquare {
  2. diceRoll += 1
  3. if diceRoll == 7 { diceRoll = 1 }
  4. switch square + diceRoll {
  5. case finalSquare:
  6. // diceRoll will move us to the final square, so the game is over
  7. break gameLoop
  8. case let newSquare where newSquare > finalSquare:
  9. // diceRoll will move us beyond the final square, so roll again
  10. continue gameLoop
  11. default:
  12. // this is a valid move, so find out its effect
  13. square += diceRoll
  14. square += board[square]
  15. }
  16. }
  17. print("Game over!")


サイコロは、各ループの最初に振られます。すぐにプレイヤーを移動するよりも、むしろループは移動の結果を考慮し、移動が許可されているかどうかを決定する為 switch 文を使用します。


注意:

上記の break 文が、gameLoop ラベルを使用しなかった場合、while 文ではなく、switch 文を抜け出すでしょう。gameLoop ラベルを使用すると、どの制御文を終了すべきかが明らかになります。


ループの次の繰り返しにジャンプする continue gameLoop を呼び出すときには gameLoop ラベルを使用する必要は厳密にはありません。ゲーム内には唯一つしかループがなく、したがってどのループに continue 文が影響を与えるのかに関して、曖昧さはありません。しかし、continue 文で gameLoop ラベルを使用しても害はありません。そうすることで、break 文と一緒にあるラベルの使用と首尾一貫し、ゲームの論理を読みやすく理解しやすくなります。


早期終了


guard 文は、if 文のように、式のブール値に応じて文を実行します。guard 文が実行された後にはコードの条件が真でなければならないことを要求するように guard 文を使用して下さい。if 文とは異なり、guard 文は条件が真でない場合実行される、else 節内のコードである、else 節が常にあります。


  1. func greet(person: [String: String]) {
  2. guard let name = person["name"] else {
  3. return
  4. }
  5. print("Hello \(name)!")
  6. guard let location = person["location"] else {
  7. print("I hope the weather is nice near you.")
  8. return
  9. }
  10. print("I hope the weather is nice in \(location).")
  11. }
  12. greet(person: ["name": "John"])
  13. // Prints "Hello John!"
  14. // Prints "I hope the weather is nice near you."
  15. greet(person: ["name": "Jane", "location": "Cupertino"])
  16. // Prints "Hello Jane!"
  17. // Prints "I hope the weather is nice in Cupertino."


guard 文の条件が満たされた場合、コードの実行は guard 文の閉じ括弧の後に続きます。条件の一部として、optuinal の結合を使用して値を代入されたすべての変数または定数は guard 文が表示された、コードブロックの残りで利用可能です。


その条件が満たされない場合、else 分岐内のコードが実行されます。その分枝は guard 文が表示されるコードブロックを終了するため制御を転送しなければなりません。それは、return,break,continue、または throw のような制御転送文でこれを行うことができ、あるいは fatalError(_:file:line:) のように返さない関数やメソッドを呼び出すことができます。


要件について、guard 文を使用すると、if 文で同じチェックをするのと比較すると、コードの可読性を向上します。これにより、通常実行されるコードを else ブロックで包みこまずに記述でき、違反した要件を処理するコードを要件の隣に保持できます。


遅延したアクション


あなたのコードの一部を実行するかどうか、または実行回数を制御できる ifwhile などの制御フロー構造とは異なり、コードの一部が実行される ときに 制御を defer (延期) します。defer ブロックを使用して、後であなたのプログラムが現在のスコープの終わりに到達したときに実行されるコードを作成します。 例えば:


  1. var score = 1
  2. if score < 10 {
  3. defer {
  4. print(score)
  5. }
  6. score += 5
  7. }
  8. // Prints "6"


上記の例では、if 文の本体を終了する前に、defer ブロック内のコードが実行されます。まず、if 文内のコードが実行され、score が 5 つずつ増加します。次に、if 文のスコープを終了する前に、遅延したコードが実行され、score が出力されます。


プログラムがそのスコープをどのように終了するかに関係なく、defer 内のコードは常に実行されます。これには、関数の早期終了、for ループの抜け出し、エラーの throw などのコードが含まれます。この動作により、defer は、手動でのメモリの割り当てと解放、低レベルのファイル記述子のオープンとクローズ、データベースでの処理の開始と終了など、ペアのアクションの発生を保証する必要がある操作に役立ちます。これは、両方のアクションを隣に記述できるためです。たとえば、以下のコードは、コードの塊内で 100 を加算および減算することにより、スコアに一時的なボーナスを与えます。


  1. var score = 3
  2. if score < 100 {
  3. score += 100
  4. defer {
  5. score -= 100
  6. }
  7. // Other code that uses the score with its bonus goes here.
  8. print(score)
  9. }
  10. // Prints "103"


同じスコープ内に複数の defer ブロックを作成した場合、最初に指定した defer ブロックが最後に実行されます。


  1. if score < 10 {
  2. defer {
  3. print(score)
  4. }
  5. defer {
  6. print("The score is:")
  7. }
  8. score += 5
  9. }
  10. // Prints "The score is:"
  11. // Prints "6"


例えば、実行時エラーやクラッシュが原因でプログラムの実行が停止した場合、遅延したコードは実行されません。ただし、遅延したコードはエラーが throw された後に実行されます。エラー処理での defer の使用については、クリーンアップ アクションの指定 を参照してください。


API 利用可能性の確認


Swift には API の利用可能性を確認するためのサポートが組み込まれていますが、与えられた展開ターゲットでは使用できない API を誤って使用しないことをそれは保証します。


コンパイラは、コード内で使用される全ての API が、プロジェクトで指定された展開ターゲット上で使用可能であることを確認するために SDK の利用情報を使用します。利用できない API を使用しようとした時、Swift は、コンパイル時にエラーを報告します。


使用したい API が実行時に利用可能かどうかに応じて、コードのブロックを条件付きで実行する、if または guard 文で 利用可能性の条件 を使用して下さい。コードのそのブロック内の API が利用可能であることを確認したときにコンパイラは利用可能の条件からの情報を使用します。


  1. if #available(iOS 10, macOS 10.12, *) {
  2. // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
  3. } else {
  4. // Fall back to earlier iOS and macOS APIs
  5. }


上記の利用可能性の条件は、iOS 内のそれを指定し、if 文の本体は iOS 10 以降のみで、macOS では macOS 10.12 以降でのみ実行します。最後の引数、* は、他の任意のプラットフォーム上で必要で指定しており、if の本体はあなたのターゲットによって指定された最小展開ターゲット上で実行します。


その一般的な形式では、利用可能性の条件は、プラットフォームの名前とバージョンのリストを取ります。iOS、macOS、watchOStvOS のようなプラットフォームの名前を使用しますが、その完全なリストは、宣言の属性 を参照してください。iOS 8 や macOS 10.10 のようにメジャーなバージョン番号を指定するのに加え、iOS 11.2.6 や macOS 10.13.3 のようなマイナーなバージョン番号を指定できます。


guard で利用可能性条件を使用すると、そのコードブロックの残りのコードに使用される利用可能情報が洗練されます。


  1. @available(macOS 10.12, *)
  2. struct ColorPreference {
  3. var bestColor = "blue"
  4. }
  5. func chooseBestColor() -> String {
  6. guard #available(macOS 10.12, *) else {
  7. return "gray"
  8. }
  9. let colors = ColorPreference()
  10. return colors.bestColor
  11. }


上記の例では、ColorPreference 構造体には macOS 10.12 以降が必要です。chooseBestColor() 関数は、利用可能性の guard で始まります。プラットフォームのバージョンが古すぎて ColorPreference を使用できない場合は、常に利用可能な動作になります。guard 文の後、macOS 10.12 以降を必要とする API を使用できます。


#available に加えて、Swift は利用不可条件を使用した反対のチェックもサポートしています。たとえば、以下の 2 つのチェックは同じことを行います。


  1. if #available(iOS 10, *) {
  2. } else {
  3. // Fallback code
  4. }
  5. if #unavailable(iOS 10) {
  6. // Fallback code
  7. }


#unavailable 形式を使用すると、チェックにフォールバックコードのみが含まれている場合に、コードがより読みやすくなります。


前:コレクション型 次:関数
















トップへ












トップへ












トップへ












トップへ
目次
Xcode の新機能

Swift について
Swift と Cocoa と Objective-C (obsolete)
Swift Blog より (obsolete)

SwiftLogo
  • Swift 5.8 全メニュー


  • Swift へようこそ

  • Swift 言語のガイド
  • 基本演算子
  • 文字列と文字
  • コレクション型
  • フロー制御
  • 関数
  • クロージャ
  • 列挙型
  • 構造体とクラス
  • プロパティ
  • メソッド
  • サブスクリプト
  • 継承
  • 初期化
  • デイニシャライザ
  • Optional の連鎖
  • エラー処理
  • 同時実行
  • 型キャスト
  • ネストした型
  • 拡張機能
  • プロトコル
  • ジェネリック(汎用)
  • 不透明な型
  • 自動参照カウント
  • メモリの安全性
  • アクセス制御
  • 高度な演算子

  • 言語リファレンス

  • マニュアルの変更履歴













  • トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ