197 lines
19 KiB
Markdown
197 lines
19 KiB
Markdown
# 2. Основные типы данных. Выражения
|
||
|
||
- [2.1. Идентификаторы](#2-1-идентификаторы)
|
||
- [2.1.1. Ключевые слова](#2-1-1-ключевые-слова)
|
||
- [2.2. Литералы](#2-2-литералы)
|
||
- [2.2.1. Логические литералы](#2-2-1-логические-литералы)
|
||
- [2.2.2. Целые литералы](#2-2-2-целые-литералы)
|
||
- [2.2.3. Литералы с плавающей запятой]()
|
||
- [2.2.4. Знаковые литералы]()
|
||
- [2.2.5. Строковые литералы]()
|
||
- [2.2.5.1. Строковые литералы: WYSIWYG, с разделителями, строки токенов и импортированные]()
|
||
- [2.2.5.2. Тип строкового литерала]()
|
||
- [2.2.6. Литералы массивов и ассоциативных массивов]()
|
||
- [2.2.7. Функциональные литералы (лямбда-функция)]()
|
||
- [2.3. Операции]()
|
||
- [2.3.1. l-значения и r-значения]()
|
||
- [2.3.2. Неявные преобразования чисел]()
|
||
- [2.3.2.1. Распространение интервала значений]()
|
||
- [2.3.3. Типы числовых операций]()
|
||
- [2.3.4. Первичные выражения]()
|
||
- [2.3.4.1. Выражение assert]()
|
||
- [2.3.4.2. Выражение mixin]()
|
||
- [2.3.4.3. Выражения is]()
|
||
- [2.3.4.4. Выражения в круглых скобках]()
|
||
- [2.3.5. Постфиксные операции]()
|
||
- [2.3.5.1. Доступ ко внутренним элементам]()
|
||
- [2.3.5.2. Увеличение и уменьшение на единицу]()
|
||
- [2.3.5.3. Вызов функции]()
|
||
- [2.3.5.4. Индексация]()
|
||
- [2.3.5.5. Срезы массивов]()
|
||
- [2.3.5.6. Создание вложенного класса]()
|
||
- [2.3.6. Унарные операции]()
|
||
- [2.3.6.1. Выражение new]()
|
||
- [2.3.6.2. Получение адреса и разыменование]()
|
||
- [2.3.6.3. Увеличение и уменьшение на единицу (префиксный вариант)]()
|
||
- [2.3.6.4. Поразрядное отрицание]()
|
||
- [2.3.6.5. Унарный плюс и унарный минус]()
|
||
- [2.3.6.6. Отрицание]()
|
||
- [2.3.6.7. Приведение типов]()
|
||
- [2.3.7. Возведение в степень]()
|
||
- [2.3.8. Мультипликативные операции]()
|
||
- [2.3.9. Аддитивные операции]()
|
||
- [2.3.10. Сдвиг]()
|
||
- [2.3.11. Выражения in]()
|
||
- [2.3.12. Сравнение]()
|
||
- [2.3.12.1. Проверка на равенство]()
|
||
- [2.3.12.2. Сравнение для упорядочивания]()
|
||
- [2.3.12.3. Неассоциативность]()
|
||
- [2.3.13. Поразрядные ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и И]()
|
||
- [2.3.14. Логическое И]()
|
||
- [2.3.15. Логическое ИЛИ]()
|
||
- [2.3.16. Тернарная условная операция]()
|
||
- [2.3.17. Присваивание]()
|
||
- [2.3.18. Выражения с запятой]()
|
||
- [2.4. Итоги и справочник]()
|
||
|
||
Если вы когда-нибудь программировали на C, C++, Java или C#, то с основными типами данных и выражениями D у вас не будет никаких затруднений. Операции со значениями основных типов – неотъемлемая часть решений многих задач программирования. Эти средства языка, в зависимости от ваших предпочтений, могут сильно облегчать либо отравлять вам жизнь. Совершенного подхода не существует; нередко поставленные цели противоречат друг другу, заставляя руководствоваться собственным субъективным мнением. Это, в свою очередь, лишает язык возможности угодить всем до единого. Слишком строгая система обременяет программиста своими запретами: он вынужден бороться с компилятором, чтобы тот принял простейшие выражения. А сделай систему типизации чересчур снисходительной – и не заметишь, как окажешься по ту сторону корректности, эффективности или того и другого вместе.
|
||
|
||
Система основных типов D творит маленькие чудеса в границах, задаваемых его принадлежностью к семейству статически типизированных компилируемых языков. Определение типа по контексту, распространение интервала значений, всевозможные стратегии перегрузки операторов и тщательно спроектированная сеть автоматических преобразований вместе делают систему типизации D дотошным, но сдержанным помощником, который если и придирается, требуя внимания, то обычно не зря.
|
||
|
||
Основные типы данных можно распределить по следующим категориям:
|
||
- *Тип без значения*: `void`, используется во всех случаях, когда формально требуется указать тип, но никакое осмысленное значение не порождается.
|
||
- *Тип null*: `typeof(null)` – тип константы `null`, используется в основном в шаблонах, неявно приводится к указателям, массивам, ассоциативным массивам и объектным типам.
|
||
- *Логический (булев) тип*: `bool` с двумя возможными значениями `true` и `false`.
|
||
- *Целые типы*: `byte`, `short`, `int` и `long`, а также их эквиваленты без знака `ubyte`, `ushort`, `uint` и `ulong`.
|
||
- *Вещественные типы с плавающей запятой*: `float`, `double` и `real`.
|
||
- *Знаковые типы*: `char`, `wchar` и `dchar`, которые на самом деле содержат числа, предназначенные для кодирования знаков Юникода.
|
||
|
||
В табл. 2.1 вкратце описаны основные типы данных D с указанием их размеров и начальных значений по умолчанию. В языке D переменная инициализируется автоматически, если вы просто определили ее, не указав начального значения. Значение по умолчанию доступно для любого типа как `<тип>.init`; например `int.init` – это ноль.
|
||
|
||
*Таблица 2.1. Основные типы данных D*
|
||
|
||
|Тип данных|Описание|Начальное значение по умолчанию|
|
||
|-|-|-|
|
||
|`void`|Без значения|`n/a`|
|
||
|`typeof(null)`|Тип константы `null`|`n/a`|
|
||
|`bool`|Логическое (булево) значение|`false`|
|
||
|`byte`|Со знаком, 8 бит|`0`|
|
||
|`ubyte`|Без знака, 8 бит|`0`|
|
||
|`short`|Со знаком, 16 бит|`0`|
|
||
|`ushort`|Без знака, 16 бит|`0`|
|
||
|`int`|Со знаком, 32 бита|`0`|
|
||
|`uint`|Без знака, 32 бита|`0`|
|
||
|`long`|Со знаком, 64 бита|`0`|
|
||
|`ulong`|Без знака, 64 бита|`0`|
|
||
|`float`|32 бита, с плавающей запятой|`float.nan`|
|
||
|`double`|64 бита, с плавающей запятой|`double.nan`|
|
||
|`real`|Наибольшее, какое только может позволить аппаратное обеспечение|`real.nan`|
|
||
|`char`|Без знака, 8 бит, в UTF-8|`0xFF`|
|
||
|`wchar`|Без знака, 16 бит, в UTF-16|`0xFFFF`|
|
||
|`dchar`|Без знака, 32 бита, в UTF-32|`0x0000FFFF`|
|
||
|
||
[В начало ⮍](#2-основные-типы-данных-выражения)
|
||
|
||
## 2.1. Идентификаторы
|
||
|
||
Идентификатор, или символ – это чувствительная к регистру строка знаков, начинающаяся с буквы или знака подчеркивания, после чего следует любое количество букв, знаков подчеркивания или цифр. Единственное исключение из этого правила: идентификаторы, начинающиеся с двух знаков подчеркивания, зарезервированы под ключевые слова самого D. Идентификаторы, начинающиеся с одного знака подчеркивания, разрешены, и в настоящее время даже принято именовать поля классов таким способом.
|
||
|
||
Интересная особенность идентификаторов D – их интернациональность: «буква» в определении выше – это не только буква латинского алфавита (от A до Z и от a до z), но и знак из универсального набора[^1], определенного в стандарте C99[^2].
|
||
|
||
Например, `abc`, `α5`, `_`, `Γ_1`, `_AbC`, `Ab9C` и `_9x` – допустимые идентификаторы, а `9abc` и `__abc` – нет.
|
||
|
||
Если перед идентификатором стоит точка (`.какЗдесь`), то компилятор ищет его в пространстве имен модуля, а не в текущем лексически близком пространстве имен. Этот префиксный оператор-точка имеет тот же приоритет, что и обычный идентификатор.
|
||
|
||
[В начало ⮍](#2-1-идентификаторы) [Наверх ⮍](#2-основные-типы-данных-выражения)
|
||
|
||
### 2.1.1. Ключевые слова
|
||
|
||
Приведенные в табл. 2.2 идентификаторы – это ключевые слова, зарезервированные языком для специального использования. Пользовательский код не может переопределять их ни при каких условиях.
|
||
|
||
*Таблица 2.2. Ключевые слова языка D*
|
||
|
||
```d
|
||
abstract else macro switch
|
||
alias enum mixin synchronized
|
||
align export module
|
||
asm extern template
|
||
assert new this
|
||
auto false nothrow throw
|
||
final null true
|
||
body finally try
|
||
bool float out typeid
|
||
break for override typeof
|
||
byte foreach
|
||
function package ubyte
|
||
case pragma uint
|
||
cast goto private ulong
|
||
catch protected union
|
||
char ifIf public unittest
|
||
class immutable pure ushort
|
||
const import
|
||
continue in real version
|
||
inout ref void
|
||
dchar int return
|
||
debug interface wchar
|
||
default invariant scope while
|
||
delegate isIs short with
|
||
deprecated static
|
||
do long struct
|
||
double lazy super
|
||
```
|
||
|
||
Некоторые из ключевых слов распознаются как первичные выражения. Например, ключевое слово `this` внутри определения метода означает текущий объект, а ключевое слово `super` как статически, так и динамически заставляет компилятор обратиться к классу-родителю текущего класса (см. главу 6). Идентификатор `$` разрешен только внутри индексного выражения или выражения получения среза и обозначает длину индексируемого массива. Идентификатор `null` обозначает пустой объект, массив или указатель.
|
||
|
||
Первичное выражение `typeid(T)` возвращает информацию о типе `T` (за дополнительной информацией обращайтесь к документации для вашей реализации компилятора).
|
||
|
||
[В начало ⮍](#2-1-1-ключевые-слова) [Наверх ⮍](#2-основные-типы-данных-выражения)
|
||
|
||
## 2.2. Литералы
|
||
|
||
### 2.2.1. Логические литералы
|
||
|
||
Логические (булевы) литералы – это `true` («истина») и `false` («ложь»).
|
||
|
||
[В начало ⮍](#2-2-1-логические-литералы) [Наверх ⮍](#2-основные-типы-данных-выражения)
|
||
|
||
### 2.2.2. Целые литералы
|
||
|
||
D работает с десятичными, восьмеричными[^3], шестнадцатеричными и двоичными целыми литералами. Десятичная константа - это последовательность цифр, возможно, с суффиксом `L`, `U`, `u`, `LU`, `Lu`, `UL` или `ul`. Вывод о типе десятичного литерала делается исходя из следующих правил:
|
||
- *нет суффикса*: если значение «помещается» в `int`, то `int`, иначе `long`;
|
||
- *только* `U`/`u`: если значение «помещается» в `uint`, то `uint`, иначе `ulong`.
|
||
- *только* `L`: тип константы - `long`.
|
||
- `U`/`u` *и* `L` *совместно*: тип константы - `ulong`.
|
||
|
||
Например:
|
||
|
||
```d
|
||
auto
|
||
a = 42, // a имеет тип int
|
||
b = 42u, // b имеет тип uint
|
||
c = 42UL, // c имеет тип ulong
|
||
d = 4_000_000_000, // long; в int не поместится
|
||
e = 4_000_000_000u, // uint; в uint не поместится
|
||
f = 5_000_000_000u; // ulong; в uint не поместится
|
||
```
|
||
|
||
Вы можете свободно вставлять в числа знаки подчеркивания (только не ставьте их в начало, иначе вы на самом деле создадите идентификатор). Знаки подчеркивания помогают сделать большое число более наглядным:
|
||
|
||
```d
|
||
auto targetSalary = 15_000_000;
|
||
```
|
||
|
||
Чтобы написать шестнадцатеричное число, используйте префикс `0x` или `0X`, за которым следует последовательность знаков `0–9`, `a–f`, `A–F` или `_`. Двоичный литерал создается с помощью префикса `0b` или `0B`, за которым идет последовательность из `0`, `1` и тех же знаков подчеркивания. Как и у десятичных чисел, у всех этих литералов может быть суффикс. Правила, с помощью которых их типы определяются по контексту, идентичны правилам для десятичных чисел.
|
||
|
||
Рисунок 2.1, заменяющий 1024 слова, кратко и точно определяет синтаксис целых литералов. Правила интерпретации автомата таковы: 1) каждое ребро «поглощает» знаки, соответствующие его ребру, 2) автомат пытается «расходовать» как можно больше знаков из входной последовательности[^4]. Достижение конечного состояния (двойной кружок) означает, что число успешно распознано.
|
||
|
||
![image-2-1](images/image-2-1.png)
|
||
|
||
***Рис. 2.1.*** *Распознавание целых литералов в языке D. Автомат пытается сделать ряд последовательных шагов (поглощая знаки, соответствующие данному ребру), пока не остановится. Останов в конечном состоянии (двойной кружок) означает, что число успешно распознано. s обозначает суффикс вида U|u|L|UL|uL|Lu|LU*
|
||
|
||
[В начало ⮍](#2-2-2-целые-литералы) [Наверх ⮍](#2-основные-типы-данных-выражения)
|
||
|
||
[^1]: Впрочем, использование нелатинских букв является дурным тоном. – *Прим. науч. ред.*
|
||
[^2]: С99 – обновленная спецификация C, в том числе добавляющая поддержку знаков Юникода. – *Прим. пер.*
|
||
[^3]: Сам язык не поддерживает восьмеричные литералы, но поскольку они присутствуют в некоторых C-подобных языках, в стандартную библиотеку был добавлен соответствующий шаблон. Теперь запись `std.conv.octal!777` аналогична записи `0777` в C. – *Прим. науч. ред.*
|
||
[^4]: Для тех, кто готов воспринимать теорию: автоматы на рис. 2.1 и 2.2 – это детерминированные конечные автоматы (ДКА).
|