Контрактное программирование в D включает в себя набор конструкций языка, позволяющий повысить качество кода путём проверок "разумности" - тестов, удостоверяющихся, что код работает согласно изначальным намерениям. Контракты доступны только в режиме отладки, и не исполняются в релизном режиме. Поэтому они не должны использоваться для проверки пользовательского ввода.
assert
Простейшая форма контрактного программирования в D -
выражение assert(...)
, которое проверяет, что заданное
условие выполнено, и останавливает программу посредством
AssertionError
в противном случае.
assert(sqrt(4) == 2);
// дополнительно, можно указать
// собственное сообщение
assert(sqrt(16) == 4, "sqrt не работает!");
in
и out
позволяют формализовать контракты для
параметров и возвращаемых значений функций.
long square_root(long x)
in {
assert(x >= 0);
} out (result) {
assert((result * result) <= x
&& (result+1) * (result+1) > x);
} body {
return cast(long)std.math
.sqrt(cast(real)x);
}
Содержимое блока in
можно перенести в тело функции,
однако при использовании такого блока намерения выражаются
более чётко. Получить возвращаемое значение в блоке out
,
чтобы затем проверить его верность, можно выражением
out(result)
.
invariant()
- специальная функция-член структур
и классов, позволяющая контролировать состояние
объекта всё время его жизни:
Поскольку все контракты удаляются в релизной сборке, пользовательский ввод
нельзя проверять с помощью контрактов. assert
'ы можно использовать
в nothrow
-функциях, поскольку они вызывают "фатальные" ошибки (Error
).
Аналог времени исполнения для assert
- std.exception.enforce
,
вызывающий исключения (Exceptions
), которые разрешено ловить.