LoginSignup
6
1

More than 1 year has passed since last update.

【Swift】rethrows とは何か、どのような時に指定するべきか

Last updated at Posted at 2022-07-06

rethrows とは何か

rethrows は関数の修飾子の一つです(throws と同様です)。
rethrows が指定された関数(ここでは便宜上、親関数と呼ぶことにします)は
引数として関数(同じく、子関数とします)を取ります。

子関数として渡された関数に throws が指定されていた場合、
子関数がエラーをスローすると親関数はそのエラーをそのままスローします。
当然、親関数の呼び出し元には try が必要です。

しかし子関数として渡された関数に throws が指定されていなかった場合、
親関数がエラーをスローすることはありません。
この場合、親関数の呼び出し元には try は不要です。

親関数の呼び出し元で子関数として渡した関数に throws が指定されていたかどうかによって、
親関数の呼び出し元に try が必要かどうかが変わる
のです。
これが rethowsthrows の違いです。

// 親関数の例
func parent(_ child: () throws -> Void) rethrows {
    try child()
}
// throws が指定された子関数の例として使う関数
func childThrows() throws { }
// throws が指定されていない子関数の例として使う関数
func childDoesNotThrow() { }

try parent(childThrows)
// ^ 子関数に throws が指定されているため、親関数の呼び出しに try が必要。
parent(childDoesNotThrow)
// ^ 子関数に throws が指定されていないため、親関数の呼び出しに try が不要。

子関数がクロージャで、throws の有無が明示されていない場合は、
暗黙的に throws が指定されていると見なされるかどうかで決まります。

// 親関数の例
func parent(_ child: () throws -> Void) rethrows {
    try child()
}

try parent { throw NSError() }
// ^ 子関数に throws が指定されていると見なされるため、親関数の呼び出しに try が必要。
parent { }
// ^ 子関数に throws が指定されていないと見なされるため、親関数の呼び出しに try が不要。

どのような時に rethrows を指定するべきか

親関数に rethrows を指定するべきなのは、次の全てを満たす場合です。

  • (1) 関数を引数に取る関数である。
  • (2) 親関数がスローするエラーは、子関数がスローしたエラーだけである。
  • (3) 子関数が、
    throws が指定されている関数の場合もあれば、
    throws が指定されていない関数の場合もある。

(1)と(2)は、親関数に rethrows を指定するための必要条件です。

(3)は必要条件ではありませんが、
子関数が常に throws が指定された関数なのであれば rethrows でなく throws でよいですし、
子関数が常に throws が指定されていない関数なのであれば rethrowsthrows も不要です。

(1)(2)(3)を全て満たす場合に、rethrows ではなく throws を指定することもできますが、
それだと子関数がthrows が指定されていない関数だった場合に、親関数がエラーをスローすることがなくなるにも関わらず、
親関数の呼び出し元に try が必要となってしまいます。

rethrows を指定した関数を定義する

親関数は次のように定義します。

  • throws 指定子を書くのと同じ場所に rethrows 指定子を書く。
func myFunc(arg: () throws -> String) rethrows -> String {
                                   // ^^^^^^^^ throws を書くのと同じ場所に書く。
    try arg()
}
  • 子関数には(実際にはエラーをスローしない関数が渡されるかもしれないが)throws 指定子を付ける。
func myFunc(arg: () throws -> Void) rethrows {
                 // ^^^^^^ throws を指定する。
    try arg()
}

あとがき

rethrows については、Swift 公式の LANGUAGE GUIDE にも書かれていないし、日本語のわかりやすい記事も見当たらなかったため、この記事を書きました。
誤りなどがございましたらご指摘いただけると幸いです。

/以上

6
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
6
1