dlang-book/09-обработка-ошибок/README.md

71 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 8. Квалификаторы типа
Квалификаторы типа выражают важные утверждения о типах языка. Эти утверждения исключительно полезны как для программиста, так и для компилятора, но их сложно выразить путем соглашений, обычного порождения подтипов (см. раздел 6.4.2) или параметризации типами (см. раздел 6.14).
Показательный пример квалификатора типа квалификатор типа `const` (введенный в языке C и доработанный в C++). Примененный к типу `T`, этот квалификатор выражает следующее утверждение: значения типа `T` можно инициализировать и читать, но не перезаписывать. Соблюдение этого ограничения гарантируется компилятором. Квалификатор `const` довольно полезен внутри модуля, поскольку гарантирует инициаторам вызовов регламентированное поведение функций. Например, сигнатура
```d
// Функция из стандартной библиотеки C
int printf(const char * format, ...);
```
обещает пользователям, что функция `printf` не будет пытаться изменить знаки, переданные в параметре `format`. Подобная гарантия также полезна при масштабной разработке, поскольку сокращает количество зависимостей, созданных немодульными изменениями. Определить такие ограничения и гарантировать подчинение им можно и посредством соглашения, но подобные соглашения неудобны, и соблюдать их трудно. D определяет три типа квалификаторов:
- `const` означает неизменяемость в рамках заданного контекста. Значение типа, заданного с ключевым словом `const`, нельзя изменить напрямую. Однако другие сущности в программе могут обладать правом перезаписывать эти данные: так у инициатора вызова функции `printf` может быть право записи в переменную `format`, а у самой функции нет.
- `immutable` означает абсолютную, контекстно-независимую неизменяемость. Значение типа, заданного с ключевым словом `immutable`, после инициализации нельзя изменить ни при каких обстоятельствах нигде в программе. Это гораздо более строгое ограничение, чем у квалификатора `const`.
- `shared` означает разделение значения между потоками.
Все они дополняют друг друга. Квалификаторы `const` и `immutable` важны для масштабной разработки. Кроме того, без квалификатора `immutable` невозможно было бы программировать в функциональном стиле, а квалификатор `const` способствует интеграции кода в функциональном стиле с кодом в объектно-ориентированном и процедурном стиле. Квалификаторы `immutable` и `shared` позволяют реализовать многопоточность. Подробное описание квалификатора `shared` и разговор о многопоточности мы отложим до главы 13. А здесь сосредоточимся на квалификаторах `const` и `immutable`.
[В начало ⮍](#8-квалификаторы-типа)
## 8.1. Квалификатор immutable
Значение типа с квалификатором `immutable` высечено на камне: сразу же после инициализации такого значения можно считать, что оно навечно прожжено в хранящей его памяти. Оно никогда не изменится за все время исполнения программы.
Форма записи типа с квалификатором такова: `‹квалификатор›(T)`, где `‹квалификатор›` одно из ключевых слов `immutable`, `const` и `shared`. Например, определим неизменяемое целое число:
```d
immutable(int) forever = 42;
```
Попытки каким-либо способом изменить значение переменной `forever` приведут к ошибке во время компиляции. Более того, `immutable(int)` это полноправный тип, как любой другой тип (он отличается от типа `int`). Например, можно присвоить ему псевдоним:
```d
alias immutable(int) StableInt;
StableInt forever = 42;
```
Определяя копию переменной `forever` с ключевым словом `auto`, вы распространите тип `immutable(int)` и на копию, так что и сама копия будет неизменяемым целым числом. Ничего особенного здесь нет, но именно этим отличаются квалификаторы типов и простые классы памяти, такие как `static` (см. раздел 5.2.5) или `ref` (см. раздел 5.2.1).
```d
unittest
{
immutable(int) forever = 42;
auto andEver = forever;
++andEver; // Ошибка! Нельзя изменять неизменяемое значение!
}
```
Значение типа с квалификатором `immutable` необязательно инициализировать константой, известной во время компиляции:
```d
void fun(int x)
{
immutable(int) xEntry = x;
...
}
```
Примененный таким образом квалификатор `immutable` оказывает услугу тем, кто будет разбираться в работе функции `fun`. С первого взгляда понятно, что переменная `xEntry` будет хранить переданное на входе в функцию значение `x` от начала и до конца тела этой функции.
В определениях с квалификатором `immutable` необязательно указывать тип он будет определен так же, как если бы вместо `immutable` стояло ключевое слово `auto`:
```d
immutable pi = 3.14, val = 42;
```
Для `pi` компилятор выводит тип `immutable(double)`, а для `val` `immutable(int)`.
[В начало ⮍](#8-1-квалификатор-immutable) [Наверх ⮍](#8-квалификаторы-типа)