0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Swift の rethrows とはなんぞ

Posted at

はじめに

Swift の rethrows を使うと、クロージャが throws を投げるかどうかに応じて関数の throws の有無が決まる という、便利なエラーハンドリングができます。しかし、「throws とは何が違うの?」「いつ rethrows を使うべき?」と疑問に思う方も多いのではないでしょうか。


1. rethrows とは?

rethrows「関数本体はエラーを投げないが、渡されたクロージャが throws の場合のみ throws になる」 という意味を持ちます。

通常の throws を使った関数と比べて、無駄な try を省略できる のが特徴です。

rethrows の例

func perform(operation: () throws -> Void) rethrows {
    try operation()
}

この perform 関数は、渡される operationthrows なら performthrows になり、そうでなければ throws なしで呼び出せます。

使い方の違い

(1) throws なしのクロージャ

perform {
    print("エラーを投げない処理")
} // try 不要

(2) throws ありのクロージャ

do {
    try perform {
        throw NSError(domain: "ExampleError", code: 1, userInfo: nil)
    }
} catch {
    print("エラー: \(error)")
}

渡すクロージャが throws なので、try が必要になります。


2. throws との違い

通常の throws を使う場合と比較すると、rethrows のメリットがよく分かります。

(1) throws を使う場合

func perform(operation: () throws -> Void) throws {
    do {
        try operation()
    } catch {
        throw NSError(domain: "ExampleError", code: 1, userInfo: nil)
    }
}

この場合、operationthrows でなくても、perform は常に throws になるので、呼び出し時に必ず try をつける必要があります。

do {
    try perform {
        print("エラーを投げない処理")
    } // try 必須!
} catch {
    print("エラー: \(error)")
}

🔻 無駄な try が発生してしまう!


(2) rethrows を使う場合

func perform(operation: () throws -> Void) rethrows {
    try operation()
}

この場合、

  • operationthrows なら try が必要。
  • operationthrows でなければ try なしで呼べる。
perform {
    print("エラーを投げない処理")
} // try 不要

エラーを投げない場合に try を省略できるので、コードがスッキリ!


3. rethrows を活用するシチュエーション

Swift の標準ライブラリでも、rethrows はさまざまな場面で活用されています。

(1) compactMap(_:)

let numbers = ["1", "2", "three", "4"]

let result = numbers.compactMap { str in Int(str) }
print(result) // [1, 2, 4]

compactMaprethrows を使っているため、クロージャが throws なら try が必要ですが、そうでなければ try なしでOK。

let result = try numbers.compactMap { str -> Int? in
    if let num = Int(str) {
        return num
    } else {
        throw NSError(domain: "InvalidNumber", code: 0, userInfo: nil)
    }
}

(2) カスタム関数で rethrows を活用

func execute(_ task: () throws -> Void) rethrows {
    try task()
}

これを使うと、

execute {
    print("エラーなしの処理")
} // try 不要
do {
    try execute {
        throw NSError(domain: "ExampleError", code: 1, userInfo: nil)
    }
} catch {
    print("エラー: \(error)")
}

不要な try を減らしつつ、エラーを投げる場面だけ try を強制できる!


4. まとめ

特性 rethrows throws
クロージャが throws の場合 throws になる throws になる
クロージャが throws でない場合 throws にならない(try 不要) throws のため try 必須
例外の変換 そのままスロー catch で処理可能

rethrows を使うメリット

クロージャが throws の場合だけ try を要求
エラーを投げない場合に try を省略できるので、コードがスッキリ!
Swift 標準ライブラリでも compactMap などで活用


📝 補足メモ

  • rethrows は関数の本体で throw することはできない
  • rethrows を使う場合、クロージャの throws をそのまま伝搬するだけ
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?