do、try、catch
CoddyのSwiftジャーニー「ロジックとフロー」セクションの一部 — レッスン 45/56。
エラーを処理するための完全な形式は、do/try/catchです:
enum DivError: Error { case byZero }
func divide(_ a: Int, _ b: Int) throws -> Int {
if b == 0 { throw DivError.byZero }
return a / b
}
do {
let r = try divide(10, 2)
print(r) // 5
} catch DivError.byZero {
print("can't divide by zero")
} catch {
print("unknown error")
}try は、エラーをスローする可能性のある呼び出しの前に置きます。呼び出しがエラーをスローした場合、制御は対応する catch にジャンプします。そうでない場合、実行は do ブロックを通り抜けて継続されます。
複数の catch 節は上から下へと実行され、switch 文と同様に最初に一致したものが適用されます。最後にある引数のない catch はすべてを捕捉する(キャッチオール)もので、コンパイラを満足させる(エラーを防ぐ)ために、ほとんどの場合これが必要になります。
チャレンジ
簡単3つのケース empty、notInteger、negative を持つ enum ParseError: Error を定義してください。
以下の動作を行うスロー関数 parsePositive(_ s: String) throws -> Int を定義してください:
- 空白をトリミングした
sが空の場合は.emptyをスローする sをIntとして解析できない場合は.notIntegerをスローする- 解析された値が
< 0の場合は.negativeをスローする - それ以外の場合は解析された値を返す
stdinから1行読み込み、do/catch ブロック内で parsePositive を呼び出します。以下を出力してください:
- 成功時は
got: <n> - 各ケースに応じて
error: empty、error: not integer、またはerror: negative
入力が 42 の場合、出力は got: 42 となります。空行の場合は error: empty となります。abc の場合は error: not integer となります。
チートシート
Swiftのエラーハンドリングは do/try/catch を使用します。Error プロトコルに準拠した enum でエラーを定義し、エラーを投げる関数には throws をマークし、throw を使用してエラーを発生させます。
enum DivError: Error { case byZero }
func divide(_ a: Int, _ b: Int) throws -> Int {
if b == 0 { throw DivError.byZero }
return a / b
}
do {
let r = try divide(10, 2)
print(r) // 5
} catch DivError.byZero {
print("can't divide by zero")
} catch {
print("unknown error") // すべてをキャッチ
}tryは、エラーを投げるすべての呼び出しの前に置く必要があります。catch句は上から下にマッチングされ、最初に一致したものが実行されます。- 最後に置かれた引数なしの
catchは、すべてのエラーをキャッチする役割を果たします。
自分で試してみよう
let line = readLine()!
// TODO: enum ParseError; func parsePositive(_:) throws -> Int;
// 3つの分岐とキャッチオールを持つ do/try/catch
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。