Menu

Исключения

Это руководство только по пользовательским исключениям (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;
}

Обратите внимание, что компилятор способен автоматически выводить атрибуты шаблонного кода.

std.exception

Важно избегать контрактного программирования для пользовательского ввода, так как контракты удаляются при компиляции в режиме 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.

Подробнее

rdmd playground.d