Menu

Винятки

Ця інструкція призначена тільки для винятків користувача. Системні винятки, як правило, зі смертельними наслідками, ніколи не повинні перехоплюватись.

Перехоплення винятків

Основною задачею винятків є перехоплення введення потенційно неприпустимих користувацьких даних. Коли трапляється виняток, відбувається проходження по стеку, доки не буде знайдений перший вiдповiдний обробник винятків.

try
{
    readText("dummyFile");
}
catch (FileException e)
{
    // ...
}

Можна мати кілька catch блоків і finally блок, який виконається незалежно від того, чи відбулася помилка. Винятки викликаються за допомогою ключового слова throw.

try
{
    throw new StringException("Ти не пройдеш!");
}
catch (FileException e)
{
    // ...
}
catch (StringException e)
{
    // ...
}
finally
{
    // ...
}

Пам'ятайте, що scope guard зазвичай є кращим рішенням за паттерн 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 знаходиться у відпустці");

Організація безпечного світу за допомогою nothrow

Компілятор D може гарантувати, що функція не може спричинити катастрофічні наслідки. Такі функції можуть бути помічені ключовим словом nothrow. Компілятор D статично забороняє кидати винятки у nothrow функції.

bool lessThan(int a, int b) nothrow
{
    writeln("небезпечний світ"); // writeln може генерувати виключення, таким чином, це заборонено
    return a < b;
}

Зверніть увагу, що компілятор може вивести атрибути для шаблонного коду автоматично.

std.exception

Важливо уникати контрактного програмування для введення користувацьких даних, так як контракти видаляються при компіляції релізної версії програми. Для зручності std.exception має ключове слово enforce, яке можна використовувати як assert, але буде виникати об'єкт Exceptions замість AssertError.

import std.exception : enforce;
float magic = 1_000_000_000;
enforce(magic + 42 - magic == 42, "Математика з плаваючою точкою файна!");

// створити власний виняток
enforce!StringException('a' != 'A', "Чуттєвий до регістру алгоритм");

Однак, std.exception містить більше цікавих речей. Наприклад, якщо помилка не матиме смертельні наслідки, можна обробити її з collect:

import std.exception : collectException;
auto e = collectException(aDangerousOperation());
if (e)
    writeln("Небезпечна операція зазнала невдачі: ", e);

Щоб перевірити, чи відбулося виключення (для тестів наприклад), використовуйте assertThrown.

Додатково

rdmd playground.d