dlang-book/02-основные-типы-данных-выр.../README.md

197 lines
19 KiB
Markdown
Raw Normal View History

2023-01-22 13:17:12 +00:00
# 2. Основные типы данных. Выражения
2023-01-22 13:41:56 +00:00
- [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-целые-литералы)
2023-01-22 13:17:12 +00:00
- [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. Выражения с запятой]()
2023-01-22 13:41:56 +00:00
- [2.4. Итоги и справочник]()
2023-01-22 13:17:12 +00:00
Если вы когда-нибудь программировали на 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-основные-типы-данных-выражения)
2023-01-22 13:41:56 +00:00
### 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`, за которым следует последовательность знаков `09`, `af`, `AF` или `_`. Двоичный литерал создается с помощью префикса `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-основные-типы-данных-выражения)
2023-01-22 13:17:12 +00:00
[^1]: Впрочем, использование нелатинских букв является дурным тоном. *Прим. науч. ред.*
[^2]: С99 обновленная спецификация C, в том числе добавляющая поддержку знаков Юникода. *Прим. пер.*
2023-01-22 13:41:56 +00:00
[^3]: Сам язык не поддерживает восьмеричные литералы, но поскольку они присутствуют в некоторых C-подобных языках, в стандартную библиотеку был добавлен соответствующий шаблон. Теперь запись `std.conv.octal!777` аналогична записи `0777` в C. *Прим. науч. ред.*
[^4]: Для тех, кто готов воспринимать теорию: автоматы на рис. 2.1 и 2.2 это детерминированные конечные автоматы (ДКА).