Глава 8, начало
This commit is contained in:
parent
f10bcce1e4
commit
4ef6fce53b
|
@ -0,0 +1,70 @@
|
||||||
|
# 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-квалификаторы-типа)
|
Loading…
Reference in New Issue