dlang-book/08-квалификаторы-типа
Alexander Zhirov b4d0baee1e Глава 8, начало 2023-02-28 11:12:50 +03:00
..
README.md Глава 8, начало 2023-02-28 11:12:50 +03:00

README.md

8. Квалификаторы типа

Квалификаторы типа выражают важные утверждения о типах языка. Эти утверждения исключительно полезны как для программиста, так и для компилятора, но их сложно выразить путем соглашений, обычного порождения подтипов (см. раздел 6.4.2) или параметризации типами (см. раздел 6.14).

Показательный пример квалификатора типа квалификатор типа const (введенный в языке C и доработанный в C++). Примененный к типу T, этот квалификатор выражает следующее утверждение: значения типа T можно инициализировать и читать, но не перезаписывать. Соблюдение этого ограничения гарантируется компилятором. Квалификатор const довольно полезен внутри модуля, поскольку гарантирует инициаторам вызовов регламентированное поведение функций. Например, сигнатура

// Функция из стандартной библиотеки 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.1. Квалификатор immutable

Значение типа с квалификатором immutable высечено на камне: сразу же после инициализации такого значения можно считать, что оно навечно прожжено в хранящей его памяти. Оно никогда не изменится за все время исполнения программы.

Форма записи типа с квалификатором такова: ‹квалификатор›(T), где ‹квалификатор› одно из ключевых слов immutable, const и shared. Например, определим неизменяемое целое число:

immutable(int) forever = 42;

Попытки каким-либо способом изменить значение переменной forever приведут к ошибке во время компиляции. Более того, immutable(int) это полноправный тип, как любой другой тип (он отличается от типа int). Например, можно присвоить ему псевдоним:

alias immutable(int) StableInt;
StableInt forever = 42;

Определяя копию переменной forever с ключевым словом auto, вы распространите тип immutable(int) и на копию, так что и сама копия будет неизменяемым целым числом. Ничего особенного здесь нет, но именно этим отличаются квалификаторы типов и простые классы памяти, такие как static (см. раздел 5.2.5) или ref (см. раздел 5.2.1).

unittest
{
    immutable(int) forever = 42;
    auto andEver = forever;
    ++andEver; // Ошибка! Нельзя изменять неизменяемое значение!
}

Значение типа с квалификатором immutable необязательно инициализировать константой, известной во время компиляции:

void fun(int x)
{
    immutable(int) xEntry = x;
    ...
}

Примененный таким образом квалификатор immutable оказывает услугу тем, кто будет разбираться в работе функции fun. С первого взгляда понятно, что переменная xEntry будет хранить переданное на входе в функцию значение x от начала и до конца тела этой функции.

В определениях с квалификатором immutable необязательно указывать тип он будет определен так же, как если бы вместо immutable стояло ключевое слово auto:

immutable pi = 3.14, val = 42;

Для pi компилятор выводит тип immutable(double), а для val immutable(int).

В начало ⮍ Наверх ⮍