Это руководство только по пользовательским исключениям (Exceptions
) - системные
ошибки (Errors
) обычно непоправимы и никогда не должны отлавливаться.
Распространённый случай для использования исключений - это проверка потенциально некорректного ввода пользовательских данных. При возникновении исключения стек будет развёрнут до первого найденного обработчика исключений.
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
. Компилятор D статически
запрещает инициировать исключения в nothrow
функциях.
bool lessThan(int a, int b) nothrow
{
writeln("unsafe world"); // вывод может инициировать исключения, поэтому такое запрещено
return a < b;
}
Обратите внимание, что компилятор способен автоматически выводить атрибуты шаблонного кода.
Важно избегать контрактного программирования для пользовательского ввода, так как
контракты удаляются при компиляции в режиме Release.
Для удобства, std.exception
предоставляет метод enforce
, который может быть
использован подобно assert
'ам, но инициирует Exception
'ы вместо AssertError
.
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
.