このガイドではユーザException
についてのみ取り扱います。
システムError
は通常致命的で、キャッチすべきではありません。
例外の一般的な例は、無効である可能性のあるユーザの入力を確認することです。 例外が投げられると、スタックは最初にマッチする例外ハンドラが見つかるまで巻き戻されます。
try
{
readText("dummyFile");
}
catch (FileException e)
{
// ...
}
複数のcatch
ブロックや、エラーが起きたかどうかに関係なく実行されるfinally
ブロックを持つことができます。
例外はthrow
によって投げられます。
try
{
throw new StringException("You shall not pass.");
}
catch (FileException e)
{
// ...
}
catch (StringException e)
{
// ...
}
finally
{
// ...
}
スコープガードが通常try-finally
パターンの良い手法であることを覚えておいてください。
Exception
から簡単に継承ができ、カスタム例外を作ることができます:
class UserNotFoundException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__) {
super(msg, file, line);
}
}
throw new UserNotFoundException("D-Man is on vacation");
nothrow
で安全な世界へDコンパイラは関数が壊滅的副作用を引き起こさないことを保証できます。
そのような関数はnothrow
キーワードで注釈することができます。
nothrow
関数内でDコンパイラは例外を投げることを静的に禁止します。
bool lessThan(int a, int b) nothrow
{
writeln("unsafe world"); // 出力は例外を投げる可能性があり、従ってこれは禁止です。
return a < b;
}
コンパイラはテンプレート化されたコードの属性を推論できることを覚えておいてください。
ユーザー入力に対するassert
による
契約プログラミング
を避けることは重要です。
リリースモードでのコンパイル時に契約は除去されてしまいます。
利便性のためにstd.exception
はenforce
を提供しており、
これはassert
のように使えますが、AssertError
のかわりにException
を投げます。
import std.exception : enforce;
float magic = 1_000_000_000;
enforce(magic + 42 - magic == 42, "Floating-point math is fun");
// カスタム例外を投げる
enforce!StringException('a' != 'A', "Case-sensitive algorithm");
しかしstd.exception
にあるのははこれだけではありません。例えばエラーが
致命的でないかもしれない時、それをcollect
することをオプトインできます:
import std.exception : collectException;
auto e = collectException(aDangerousOperation());
if (e)
writeln("The dangerous operation failed with ", e);
テスト内で例外が投げられるかどうかテストするためには、assertThrown
を使います。