Compare commits
41 Commits
b90bbc94c2
...
f0f0c72675
Author | SHA1 | Date |
---|---|---|
|
f0f0c72675 | |
|
8f7b9d5087 | |
|
4299579a93 | |
|
45190add84 | |
|
31a3cdc754 | |
|
22708324a5 | |
|
09fcedd370 | |
|
85400768e2 | |
|
723bb7dc56 | |
|
902c92d179 | |
|
55e58d277d | |
|
59446ae9e5 | |
|
3c8803c966 | |
|
3d1a3ae0b2 | |
|
ce34e74f04 | |
|
ca6cd093fa | |
|
c6967b5418 | |
|
6ef8226088 | |
|
e77d981888 | |
|
bfa6c8d96c | |
|
0f7274bd91 | |
|
13d3d50ecd | |
|
4673aaf466 | |
|
460bc91771 | |
|
db270b5c1b | |
|
9536065c69 | |
|
8b2176ad8a | |
|
d0026ae566 | |
|
7057f2ff5d | |
|
727e56a225 | |
|
671abb735c | |
|
740eda991e | |
|
b7c4623669 | |
|
7c95077668 | |
|
b8800a6e4a | |
|
b3bc331c14 | |
|
6803291dc3 | |
|
3e3e3455fe | |
|
90edfbb040 | |
|
d20a62d467 | |
|
8bd685439d |
|
@ -9,22 +9,14 @@
|
|||
|
||||
Обретая силу в простоте, язык программирования порождает красоту.
|
||||
|
||||
Поиск компромисса при противоречивых требованиях – сложная зада
|
||||
ча, для решения которой создателю языка требуется не только знание теоретических принципов и практической стороны дела, но и хороший вкус. Проектирование языка программирования – это последняя ступень мастерства в разработке программ.
|
||||
Поиск компромисса при противоречивых требованиях – сложная задача, для решения которой создателю языка требуется не только знание теоретических принципов и практической стороны дела, но и хороший вкус. Проектирование языка программирования – это последняя ступень мастерства в разработке программ.
|
||||
|
||||
D – это язык, который последовательно старается правильно действовать в пределах выбранных им ограничений, таких как доступ систем
|
||||
ного уровня к вычислительным ресурсам, высокая производительность и синтаксическая простота, к которой стремятся все произошедшие от C языки. Стараясь правильно действовать, D порой поступает традиционно – как другие языки, а порой ломает традиции с помощью свежего, инновационного решения. Иногда это приводило к пересмотру принципов, которым, казалось, D никогда не изменит. Например, большие фрагменты программного кода, а то и целые программы, могут быть написаны с помощью хорошо определенного, не допускающего ошибок памяти «безопасного подмножества» D. Ценой небольшого ограничения доступа на системном уровне приобретается огромное преимущество при отладке программ. D заинтересует вас, если для вас важны следующие аспекты:
|
||||
- *Производительность*. D – это язык для системного программирования. Его модель памяти, несмотря на сильную типизацию, совмес
|
||||
тима с моделью памяти C. Функции на D могут вызывать функции на C, а функции на C могут использовать функции D без каких-либо
|
||||
промежуточных преобразований.
|
||||
- *Выразительность*. D нельзя назвать небольшим, минималистичным языком, но его удельная мощность достаточно велика. Он по
|
||||
зволяет определять наглядные, не требующие объяснений инструкции, точно моделирующие сложные реалии.
|
||||
- *«Крутящий момент»*. Любой лихач-«самоделкин» скажет вам, что мощность еще не все – было бы где ее применить. На одних языках
|
||||
лучше всего пишутся маленькие программы. Синтаксические излишества других оправдываются только начиная с определенного объема программ. D одинаково эффективно помогает справляться и с короткими сценариями, и с большими программами, и для него отнюдь не редкость целый проект, органично вырастающий из простенького скрипта в единственном файле.
|
||||
- *Параллельные вычисления*. Подход к параллельным вычислениям – несомненное отличие D от похожих языков, отражающее разрыв ме
|
||||
жду современными аппаратными решениями и архитектурой компьютеров прошлого. D покончил с проклятьем неявного разделения памяти (хотя и допускает статически проверенное, явно заданное разделение) и поощряет независимые потоки, которые «общаются» друг с другом посредством сообщений.
|
||||
- *Обобщенное программирование*. Идея обобщенного кода, манипули рующего другим кодом, была впервые реализована в мощных макро
|
||||
сах Лиспа, затем в шаблонах C++, обобщенных классах Java и схожих конструкциях других языков. D также предлагает невероятно мощные механизмы обобщенного и порождающего программирования.
|
||||
D – это язык, который последовательно старается правильно действовать в пределах выбранных им ограничений, таких как доступ системного уровня к вычислительным ресурсам, высокая производительность и синтаксическая простота, к которой стремятся все произошедшие от C языки. Стараясь правильно действовать, D порой поступает традиционно – как другие языки, а порой ломает традиции с помощью свежего, инновационного решения. Иногда это приводило к пересмотру принципов, которым, казалось, D никогда не изменит. Например, большие фрагменты программного кода, а то и целые программы, могут быть написаны с помощью хорошо определенного, не допускающего ошибок памяти «безопасного подмножества» D. Ценой небольшого ограничения доступа на системном уровне приобретается огромное преимущество при отладке программ. D заинтересует вас, если для вас важны следующие аспекты:
|
||||
- *Производительность*. D – это язык для системного программирования. Его модель памяти, несмотря на сильную типизацию, совместима с моделью памяти C. Функции на D могут вызывать функции на C, а функции на C могут использовать функции D без каких-либо промежуточных преобразований.
|
||||
- *Выразительность*. D нельзя назвать небольшим, минималистичным языком, но его удельная мощность достаточно велика. Он позволяет определять наглядные, не требующие объяснений инструкции, точно моделирующие сложные реалии.
|
||||
- *«Крутящий момент»*. Любой лихач-«самоделкин» скажет вам, что мощность еще не все – было бы где ее применить. На одних языках лучше всего пишутся маленькие программы. Синтаксические излишества других оправдываются только начиная с определенного объема программ. D одинаково эффективно помогает справляться и с короткими сценариями, и с большими программами, и для него отнюдь не редкость целый проект, органично вырастающий из простенького скрипта в единственном файле.
|
||||
- *Параллельные вычисления*. Подход к параллельным вычислениям – несомненное отличие D от похожих языков, отражающее разрыв между современными аппаратными решениями и архитектурой компьютеров прошлого. D покончил с проклятьем неявного разделения памяти (хотя и допускает статически проверенное, явно заданное разделение) и поощряет независимые потоки, которые «общаются» друг с другом посредством сообщений.
|
||||
- *Обобщенное программирование*. Идея обобщенного кода, манипули рующего другим кодом, была впервые реализована в мощных макросах Лиспа, затем в шаблонах C++, обобщенных классах Java и схожих конструкциях других языков. D также предлагает невероятно мощные механизмы обобщенного и порождающего программирования.
|
||||
- *Эклектизм*. D подразумевает, что каждая парадигма программирования ориентирована на свою задачу разработки. Поэтому он предполагает высокоинтегрированный объединенный стиль программирования, а не Единственно Верный Подход.
|
||||
- *«Это мои принципы. А если они вам не нравятся, то у меня есть и другие»*[^1]. D старается всегда следовать своим принципам устройства языка. Иногда они идут вразрез с соображениями сложности реализации и трудностей использования и, главное, с человеческой природой, которая не всегда находит скрытую логику здравой и интуитивно понятной. В таких случаях все языки полагаются на собственное бесконечно субъективное понимание баланса, гибкости и – особенно – хорошего вкуса. На мой взгляд, D как минимум неплохо смотрится на фоне других языков, разработчикам которых приходилось принимать решения того же плана.
|
||||
|
||||
|
|
|
@ -72,25 +72,25 @@
|
|||
|
||||
*Таблица 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`|
|
||||
| Тип данных | Описание | Начальное<br>значение<br>по умолчанию |
|
||||
| --- | --- | --- |
|
||||
| `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-основные-типы-данных-выражения)
|
||||
|
||||
|
@ -224,22 +224,22 @@ auto
|
|||
|
||||
*Таблица 2.3. Экранирующие последовательности в D*
|
||||
|
||||
|Escape-последовательность|Тип|Описание|
|
||||
|-|-|-|
|
||||
|`\"`|`char`|Двойная кавычка (если двусмысленно)|
|
||||
|`\\`|`char`|Обратная косая черта|
|
||||
|`\a`|`char`|Звуковой сигнал (Bell, ASCII 7)|
|
||||
|`\b`|`char`|Backspace (ASCII 8)|
|
||||
|`\f`|`char`|Смена страницы (ASCII 12)|
|
||||
|`\n`|`char`|Перевод строки (ASCII 10)|
|
||||
|`\r`|`char`|Возврат каретки (ASCII 13)|
|
||||
|`\t`|`char`|Табуляция (ASCII 9)|
|
||||
|`\v`|`char`|Вертикальная табуляция (ASCII 11)|
|
||||
|`\<1–3 восьмеричные цифры>`|`char`|Знак UTF-8 в восьмеричном представлении (не больше 377<sub>8</sub>)|
|
||||
|`\x<2 шестнадцатеричные цифры>`|`char`|Знак UTF-8 в шестнадцатеричном представлении|
|
||||
|`\u<4 шестнадцатеричные цифры>`|`wchar`|Знак UTF-16 в шестнадцатеричном представлении|
|
||||
|`\U<8 шестнадцатеричных цифр>`|`dchar`|Знак UTF-32 в шестнадцатеричном представлении|
|
||||
|`\&<имя знака>;`|`dchar`|Имя знака Юникод|
|
||||
| Escape<br>последовательность | Тип | Описание |
|
||||
| --- | --- | --- |
|
||||
| `\"` | `char` | Двойная кавычка (если двусмысленно) |
|
||||
| `\\` | `char` | Обратная косая черта |
|
||||
| `\a` | `char` | Звуковой сигнал (Bell, ASCII 7) |
|
||||
| `\b` | `char` | Backspace (ASCII 8) |
|
||||
| `\f` | `char` | Смена страницы (ASCII 12) |
|
||||
| `\n` | `char` | Перевод строки (ASCII 10) |
|
||||
| `\r` | `char` | Возврат каретки (ASCII 13) |
|
||||
| `\t` | `char` | Табуляция (ASCII 9) |
|
||||
| `\v` | `char` | Вертикальная табуляция (ASCII 11) |
|
||||
| `\<1–3 восьмеричные цифры>` | `char` | Знак UTF-8 в восьмеричном представлении (не больше 377<sub>8</sub>) |
|
||||
| `\x<2 шестнадцатеричные цифры>` | `char` | Знак UTF-8 в шестнадцатеричном представлении |
|
||||
| `\u<4 шестнадцатеричные цифры>` | `wchar` | Знак UTF-16 в шестнадцатеричном представлении |
|
||||
| `\U<8 шестнадцатеричных цифр>` | `dchar` | Знак UTF-32 в шестнадцатеричном представлении |
|
||||
| `\&<имя знака>;` | `dchar` | Имя знака Юникод |
|
||||
|
||||
[В начало ⮍](#2-2-4-знаковые-литералы) [Наверх ⮍](#2-основные-типы-данных-выражения)
|
||||
|
||||
|
@ -307,7 +307,7 @@ auto b = q{ № }; // Ошибка! "№" - не токен язы
|
|||
auto a = q{ __EOF__ }; // Ошибка! __EOF__ - не токен, а конец файла
|
||||
```
|
||||
|
||||
Также D определяет еще один вид строковых литералов – шестнадцатеричную строку, то есть строку, состоящую из шестнадцатеричных цифр и пробелов (пробелы игнорируются) между `x"` и `"`. Шестнадцатеричные строки могут быть полезны для определения сырых данных; компилятор не пытается интерпретировать содержимое литералов никак знаки Юникода, ни как-то еще – только как шестнадцатеричные цифры. Пробелы внутри строк игнорируются.
|
||||
Также D определяет еще один вид строковых литералов – шестнадцатеричную строку, то есть строку, состоящую из шестнадцатеричных цифр и пробелов (пробелы игнорируются) между `x"` и `"`. Шестнадцатеричные строки могут быть полезны для определения сырых данных; компилятор не пытается интерпретировать содержимое литералов ни как знаки Юникода, ни как-то еще – только как шестнадцатеричные цифры. Пробелы внутри строк игнорируются.
|
||||
|
||||
```d
|
||||
auto
|
||||
|
@ -707,21 +707,21 @@ bool
|
|||
|
||||
*Таблица 2.4. Зависимости для значения `Идентификатор` в выражении `is(Тип Идентификатор == Вид)`*
|
||||
|
||||
|Вид|Идентификатор – псевдоним для...|
|
||||
|-|-|
|
||||
|`struct`|`Тип`|
|
||||
|`union`|`Тип`|
|
||||
|`class`|`Тип`|
|
||||
|`interface`|`Тип`|
|
||||
|`enum`|Базовый тип перечисления|
|
||||
|`function`|Кортеж типов аргументов функции|
|
||||
|`delegate`|Функциональный тип `delegate`|
|
||||
|`super`|Родительский класс|
|
||||
|`const`|`Тип`|
|
||||
|`immutable`|`Тип`|
|
||||
|`inout`|`Тип`|
|
||||
|`shared`|`Тип`|
|
||||
|`return`|Тип, возвращаемый функцией, оператором `delegate` или указателем на функцию|
|
||||
| Вид | Идентификатор – псевдоним для ... |
|
||||
| --- | --- |
|
||||
| `struct` | `Тип` |
|
||||
| `union` | `Тип` |
|
||||
| `class` | `Тип` |
|
||||
| `interface` | `Тип` |
|
||||
| `enum` | Базовый тип перечисления |
|
||||
| `function` | Кортеж типов аргументов функции |
|
||||
| `delegate` | Функциональный тип `delegate` |
|
||||
| `super` | Родительский класс |
|
||||
| `const` | `Тип` |
|
||||
| `immutable` | `Тип` |
|
||||
| `inout` | `Тип` |
|
||||
| `shared` | `Тип` |
|
||||
| `return` | Тип, возвращаемый функцией, оператором `delegate` или указателем на функцию |
|
||||
|
||||
[Исходный код](src/chapter-2-3-4-3/)
|
||||
|
||||
|
@ -934,19 +934,11 @@ foreach (ref row; matrix)
|
|||
|
||||
### 2.3.10. Сдвиг
|
||||
|
||||
В языке D есть три операции сдвига, в каждой из которых участвуют
|
||||
два целочисленных операнда: `a << b`, `a >> b` и `a >>> b`. Во всех случаях
|
||||
значение `b` должно иметь тип без знака; значение со знаком необходимо
|
||||
привести к значению беззнакового типа (разумеется, предварительно
|
||||
убедившись, что `b >= 0`; результат сдвига на отрицательное количество
|
||||
разрядов непредсказуем). `a << b` сдвигает a влево (то есть в направлении
|
||||
В языке D есть три операции сдвига, в каждой из которых участвуют два целочисленных операнда: `a << b`, `a >> b` и `a >>> b`. Во всех случаях значение `b` должно иметь тип без знака; значение со знаком необходимо привести к значению беззнакового типа (разумеется, предварительно убедившись, что `b >= 0`; результат сдвига на отрицательное количество разрядов непредсказуем). `a << b` сдвигает a влево (то есть в направлении
|
||||
самого старшего разряда `a`) на `b` бит, а `a >> b` сдвигает `a` вправо на `b` бит.
|
||||
Если `a` – отрицательное число, знак после сдвига сохраняется.
|
||||
|
||||
`a >>> b` – это беззнаковый сдвиг независимо от знаковости `a`. Это означа
|
||||
ет, что ноль гарантированно займет самый старший разряд `a`. Проил
|
||||
люстрируем сюрпризы, которые готовит применение операции сдвига
|
||||
к числам со знаком:
|
||||
`a >>> b` – это беззнаковый сдвиг независимо от знаковости `a`. Это означает, что ноль гарантированно займет самый старший разряд `a`. Проиллюстрируем сюрпризы, которые готовит применение операции сдвига к числам со знаком:
|
||||
|
||||
```d
|
||||
int a = -1; // То есть 0xFFFF_FFFF
|
||||
|
@ -1182,85 +1174,85 @@ int c = (a = b, b = 7, 8);
|
|||
|
||||
*Таблица 2.5. Выражения D порядке убывания приоритета*
|
||||
|
||||
|Выражение|Описание|
|
||||
|-|-|
|
||||
|`<идентификатор>`|Идентификатор (см. раздел [2.1](#2-1-идентификаторы))|
|
||||
|`.<идентификатор>`|Идентификатор, доступный в пространстве имен модуля (в обход всех друг пространств имен) (см. раздел [2.1](#2-1-идентификаторы))|
|
||||
|`this`|Текущий объект внутри метода (см. раздел [2.1.1](#2-1-1-ключевые-слова))|
|
||||
|`super`|Направляет поиск идентификаторов и динамический поиск методов в пространство имен объекта-родителя (см. раздел [2.1.1](#2-1-1-ключевые-слова))|
|
||||
|`$`|Текущий размер массива (допустимо использовать `$` внутри индексирующего выражения или выражения получения среза) (см. раздел [2.1.1](#2-1-1-ключевые-слова))|
|
||||
|`null`|«Нулевая» ссылка, массив или указатель (см. раздел [2.1.1](#2-1-1-ключевые-слова))|
|
||||
|`typedi(T)`|Получить объект `TypeInfo`, ассоциированный с `T` (см. раздел [2.1.1](#2-1-1-ключевые-слова))|
|
||||
|`true`|Логическое значение «истина» (см. раздел [2.2.1](#2-2-1-логические-литералы))|
|
||||
|`false`|Логическое значение «ложь» (см. раздел [2.2.1](#2-2-1-логические-литералы))|
|
||||
|`<число>`|Числовой литерал (см. раздел [2.2.2](#2-2-2-целые-литералы), см. раздел [2.2.3](#2-2-3-литералы-с-плавающей-запятой))|
|
||||
|`<знак>`|Знаковый литерал (см. раздел [2.2.4](#2-2-4-знаковые-литералы))|
|
||||
|`<строка>`|Строковый литерал (см. раздел [2.2.5](#2-2-5-строковые-литералы))|
|
||||
|`<массив>`|Литерал массива (см. раздел [2.2.6](#2-2-6-литералы-массивов-и-ассоциативных-массивов))|
|
||||
|`<функция>`|Функциональный литерал (см. раздел [2.2.7](#2-2-7-функциональные-литералы))|
|
||||
|`assert(a)`|В режиме отладки, если a не является ненулевым значением, выполнение программы прерывается; в режиме итоговой сборки (release) ничего не происходит (см. раздел [2.3.4.1](#2-3-4-1-выражение-assert))|
|
||||
|`assert(a, b)`|То же, но к сообщению об ошибке добавляется `b` (см. раздел [2.3.4.1](#2-3-4-1-выражение-assert))|
|
||||
|`mixin(a)`|Выражение `mixin` (см. раздел [2.3.4.2](#2-3-4-2-выражение-mixin))|
|
||||
|`<IsExpr>`|Выражение `is` (см. раздел [2.3.4.3](#2-3-4-3-выражения-is))|
|
||||
|`( a )`|Выражение в круглых скобках (см. раздел [2.3.4.4](#2-3-4-4-выражения-в-круглых-скобках))|
|
||||
|`a.b`|Доступ к вложенным элементам (см. раздел [2.3.5.1](#2-3-5-1-доступ-ко-внутренним-элементам))|
|
||||
|`a++`|Постфиксный вариа нт операции увеличения на единицу (см. раздел [2.3.5.2](#2-3-5-2-увеличение-и-уменьшение-на-единицу))|
|
||||
|`a--`|Постфиксный вариант операции уменьшения на единицу (см. раздел [2.3.5.2](#2-3-5-2-увеличение-и-уменьшение-на-единицу))|
|
||||
|`a(<арг>опционально)`|Оператор вызова функции (`<арг>опционально = ` необязательный список аргументов, разделенных запятыми) (см. раздел [2.3.5.3](#2-3-5-3-вызов-функции))|
|
||||
|`a[<арг>]`|Оператор индексации (`<арг> = ` список аргументов, разделенных запятыми) (см. раздел [2.3.5.4](#2-3-5-4-индексация))|
|
||||
|`a[]`|Срез в размере всего массива (см. раздел [2.3.5.5](#2-3-5-5-срезы-массивов))|
|
||||
|`a[b .. c]`|Срез (см. раздел [2.3.5.5](#2-3-5-5-срезы-массивов))|
|
||||
|`a.<выражение new>`|Создание экземпляра вложенного класса (см. раздел [2.3.5.6](#2-3-5-6-создание-вложенного-класса))|
|
||||
|`&a`|Получение адреса (см. раздел [2.3.6.2](#2-3-6-2-получение-адреса-и-разыменование))|
|
||||
|`++a`|Префиксный вариант операции увеличения на единицу (см. раздел [2.3.6.3](#2-3-6-3-увеличение-и-уменьшение-на-единицу-префиксный-вариант))|
|
||||
|`--a`|Префиксный вариант операции уменьшения на единицу (см. раздел [2.3.6.3](#2-3-6-3-увеличение-и-уменьшение-на-единицу-префиксный-вариант))|
|
||||
|`*a`|Разыменование (см. раздел [2.3.6.2](#2-3-6-2-получение-адреса-и-разыменование))|
|
||||
|`-a`|Унарный минус (см. раздел [2.3.6.5](#2-3-6-5-унарный-плюс-и-унарный-минус))|
|
||||
|`+a`|Унарный плюс (см. раздел [2.3.6.5](#2-3-6-5-унарный-плюс-и-унарный-минус))|
|
||||
|`!a`|Отрицание (см. раздел [2.3.6.6](#2-3-6-6-отрицание))|
|
||||
|`~a`|Поразрядное отрицание (см. раздел [2.3.6.4](#2-3-6-4-поразрядное-отрицание))|
|
||||
|`(T).a`|Доступ к статическим внутренним элементам|
|
||||
|`cast(T) a`|Приведение выражения `a` к типу `T`|
|
||||
|`<выражение new>`|Создание объекта (см. раздел [2.3.6.1](#2-3-6-1-выражение-new))|
|
||||
|`a ^^ b`|Возведение в степень (см. раздел [2.3.7](#2-3-7-возведение-в-степень))|
|
||||
|`a * b`|Умножение (см. раздел [2.3.8](#2-3-8-мультипликативные-операции))|
|
||||
|`a / b`|Деление (см. раздел [2.3.8](#2-3-8-мультипликативные-операции))|
|
||||
|`a % b`|Получение остатка от деления (см. раздел [2.3.8](#2-3-8-мультипликативные-операции))|
|
||||
|`a + b`|Сложение (см. раздел [2.3.9](#2-3-9-аддитивные-операции))|
|
||||
|`a - b`|Вычитание (см. раздел [2.3.9](#2-3-9-аддитивные-операции))|
|
||||
|`a ~ b`|Конкатенация(см. раздел [2.3.9](#2-3-9-аддитивные-операции))|
|
||||
|`a << b`|Сдвиг влево (см. раздел [2.3.10](#2-3-10-сдвиг))|
|
||||
|`a >> b`|Сдвиг вправо (см. раздел [2.3.10](#2-3-10-сдвиг))|
|
||||
|`a >>> b`|Беззнаковый сдвиг вправо (старший разряд сбрасывается независимо от типа и значения `a`) (см. раздел [2.3.10](#2-3-10-сдвиг))|
|
||||
|`a in b`|Проверка на принадлежность для ассоциативных массивов (см. раздел [2.3.11](#2-3-11-выражения-in))|
|
||||
|`a == b`|Проверка на равенство; все операторы этой группы неассоциативны; например, выражение `a == b == c` некорректно (см. раздел [2.3.12.1](#2-3-12-1-проверка-на-равенство))|
|
||||
|`a != b`|Проверка на неравенство (см. раздел [2.3.12.1](#2-3-12-1-проверка-на-равенство))|
|
||||
|`a is b`|Проверка на идентичность (`true`, если и только если `a` и `b` ссылаются на один и тот же объект) (см. раздел [2.3.12.1](#2-3-12-1-проверка-на-равенство))|
|
||||
|`a !is b`|То же, что `!(a is b)`|
|
||||
|`a < b`|Меньше (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания))|
|
||||
|`a <= b`|Меньше или равно (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания))|
|
||||
|`a > b`|Больше (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания))|
|
||||
|`a >= b`|Больше или равно (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания))|
|
||||
|`a \| b`|Поразрядное **ИЛИ** (см. раздел [2.3.13](#2-3-13-поразрядные-или-исключающее-или-и-и))|
|
||||
|`a ^ b`|Поразрядное **ИСКЛЮЧАЮЩЕЕ ИЛИ** (см. раздел [2.3.13](#2-3-13-поразрядные-или-исключающее-или-и-и))|
|
||||
|`a & b`|Поразрядное **И** (см. раздел [2.3.13](#2-3-13-поразрядные-или-исключающее-или-и-и))|
|
||||
|`a && b`|Логическое **И** (`b` может иметь тип `void`) (см. раздел [2.3.14](#2-3-14-логическое-и))|
|
||||
|`a \|\| b`|Логическое **ИЛИ** (`b` может иметь тип `void`) (см. раздел [2.3.15](#2-3-15-логическое-или))|
|
||||
|`a ? b : c`|Тернарная условная операция; если операнд `a` имеет ненулевое значение, то `b`, иначе `с` (см. раздел [2.3.16](#2-3-16-тернарная-условная-операция))|
|
||||
|`a = b`|Присваивание; все операторы присваивания этой группы ассоциативны справа; например `a *= b += c` – то же, что и `a *= (b += c)` (см. раздел [2.3.17](#2-3-17-присваивание))|
|
||||
|`a += b`|Сложение «на месте»; выражения со всеми операторами вида `a ω= b`, работающими по принципу «вычислить и присвоить», вычисляются в следующем порядке: **1)** `a` (должно быть l-значением), **2)** `b` и **3)** `al = al ω b`, где `al` – l-значение, получившееся в результате вычисления `a`|
|
||||
|`a -= b`|Вычитание «на месте»|
|
||||
|`a *= b`|Умножение «на месте»|
|
||||
|`a /= b`|Деление «на месте»|
|
||||
|`a %= b`|Получение остатка от деления «на месте»|
|
||||
|`a &= b`|Поразрядное **И** «на месте»|
|
||||
|`a \|= b`|Поразрядное **ИЛИ** «на месте»|
|
||||
|`a ^= b`|Поразрядное **ИСКЛЮЧАЮЩЕЕ ИЛИ** «на месте»|
|
||||
|`a ~= b`|Конкатенация «на месте» (присоединение `b` к `a`)|
|
||||
|`a <<= b`|Сдвиг влево «на месте»|
|
||||
|`a >>= b`|Сдвиг вправо «на месте»|
|
||||
|`a >>>= b`|Беззнаковый сдвиг вправо «на месте»|
|
||||
|`a, b`|Последовательность выражений; выражения вычисляются слева направо, результатом операции становится самое правое выражение (см. раздел [2.3.18](#2-3-18-выражения-с-запятой))|
|
||||
| Выражение | Описание |
|
||||
| --- | --- |
|
||||
| `<идентификатор>` | Идентификатор (см. раздел [2.1](#2-1-идентификаторы)) |
|
||||
| `.<идентификатор>` | Идентификатор, доступный в пространстве имен модуля (в обход всех друг пространств имен) (см. раздел [2.1](#2-1-идентификаторы)) |
|
||||
| `this` | Текущий объект внутри метода (см. раздел [2.1.1](#2-1-1-ключевые-слова)) |
|
||||
| `super` | Направляет поиск идентификаторов и динамический поиск методов в пространство имен объекта-родителя (см. раздел [2.1.1](#2-1-1-ключевые-слова)) |
|
||||
| `$` | Текущий размер массива (допустимо использовать `$` внутри индексирующего выражения или выражения получения среза) (см. раздел [2.1.1](#2-1-1-ключевые-слова)) |
|
||||
| `null` | «Нулевая» ссылка, массив или указатель (см. раздел [2.1.1](#2-1-1-ключевые-слова)) |
|
||||
| `typedi(T)` | Получить объект `TypeInfo`, ассоциированный с `T` (см. раздел [2.1.1](#2-1-1-ключевые-слова)) |
|
||||
| `true` | Логическое значение «истина» (см. раздел [2.2.1](#2-2-1-логические-литералы)) |
|
||||
| `false` | Логическое значение «ложь» (см. раздел [2.2.1](#2-2-1-логические-литералы)) |
|
||||
| `<число>` | Числовой литерал (см. раздел [2.2.2](#2-2-2-целые-литералы), см. раздел [2.2.3](#2-2-3-литералы-с-плавающей-запятой)) |
|
||||
| `<знак>` | Знаковый литерал (см. раздел [2.2.4](#2-2-4-знаковые-литералы)) |
|
||||
| `<строка>` | Строковый литерал (см. раздел [2.2.5](#2-2-5-строковые-литералы)) |
|
||||
| `<массив>` | Литерал массива (см. раздел [2.2.6](#2-2-6-литералы-массивов-и-ассоциативных-массивов)) |
|
||||
| `<функция>` | Функциональный литерал (см. раздел [2.2.7](#2-2-7-функциональные-литералы)) |
|
||||
| `assert(a)` | В режиме отладки, если a не является ненулевым значением, выполнение программы прерывается;<br>в режиме итоговой сборки (release) ничего не происходит (см. раздел [2.3.4.1](#2-3-4-1-выражение-assert)) |
|
||||
| `assert(a, b)` | То же, но к сообщению об ошибке добавляется `b` (см. раздел [2.3.4.1](#2-3-4-1-выражение-assert)) |
|
||||
| `mixin(a)` | Выражение `mixin` (см. раздел [2.3.4.2](#2-3-4-2-выражение-mixin)) |
|
||||
| `<IsExpr>` | Выражение `is` (см. раздел [2.3.4.3](#2-3-4-3-выражения-is)) |
|
||||
| `( a )` | Выражение в круглых скобках (см. раздел [2.3.4.4](#2-3-4-4-выражения-в-круглых-скобках)) |
|
||||
| `a.b` | Доступ к вложенным элементам (см. раздел [2.3.5.1](#2-3-5-1-доступ-ко-внутренним-элементам)) |
|
||||
| `a++` | Постфиксный вариа нт операции увеличения на единицу (см. раздел [2.3.5.2](#2-3-5-2-увеличение-и-уменьшение-на-единицу)) |
|
||||
| `a--` | Постфиксный вариант операции уменьшения на единицу (см. раздел [2.3.5.2](#2-3-5-2-увеличение-и-уменьшение-на-единицу)) |
|
||||
| `a(<арг>опционально)` | Оператор вызова функции (`<арг>опционально = ` необязательный список аргументов, разделенных запятыми) (см. раздел [2.3.5.3](#2-3-5-3-вызов-функции)) |
|
||||
| `a[<арг>]` | Оператор индексации (`<арг> = ` список аргументов, разделенных запятыми) (см. раздел [2.3.5.4](#2-3-5-4-индексация)) |
|
||||
| `a[]` | Срез в размере всего массива (см. раздел [2.3.5.5](#2-3-5-5-срезы-массивов)) |
|
||||
| `a[b .. c]` | Срез (см. раздел [2.3.5.5](#2-3-5-5-срезы-массивов)) |
|
||||
| `a.<выражение new>` | Создание экземпляра вложенного класса (см. раздел [2.3.5.6](#2-3-5-6-создание-вложенного-класса)) |
|
||||
| `&a` | Получение адреса (см. раздел [2.3.6.2](#2-3-6-2-получение-адреса-и-разыменование)) |
|
||||
| `++a` | Префиксный вариант операции увеличения на единицу (см. раздел [2.3.6.3](#2-3-6-3-увеличение-и-уменьшение-на-единицу-префиксный-вариант)) |
|
||||
| `--a` | Префиксный вариант операции уменьшения на единицу (см. раздел [2.3.6.3](#2-3-6-3-увеличение-и-уменьшение-на-единицу-префиксный-вариант)) |
|
||||
| `*a` | Разыменование (см. раздел [2.3.6.2](#2-3-6-2-получение-адреса-и-разыменование)) |
|
||||
| `-a` | Унарный минус (см. раздел [2.3.6.5](#2-3-6-5-унарный-плюс-и-унарный-минус)) |
|
||||
| `+a` | Унарный плюс (см. раздел [2.3.6.5](#2-3-6-5-унарный-плюс-и-унарный-минус)) |
|
||||
| `!a` | Отрицание (см. раздел [2.3.6.6](#2-3-6-6-отрицание)) |
|
||||
| `~a` | Поразрядное отрицание (см. раздел [2.3.6.4](#2-3-6-4-поразрядное-отрицание)) |
|
||||
| `(T).a` | Доступ к статическим внутренним элементам |
|
||||
| `cast(T) a` | Приведение выражения `a` к типу `T` |
|
||||
| `<выражение new>` | Создание объекта (см. раздел [2.3.6.1](#2-3-6-1-выражение-new)) |
|
||||
| `a ^^ b` | Возведение в степень (см. раздел [2.3.7](#2-3-7-возведение-в-степень)) |
|
||||
| `a * b` | Умножение (см. раздел [2.3.8](#2-3-8-мультипликативные-операции)) |
|
||||
| `a / b` | Деление (см. раздел [2.3.8](#2-3-8-мультипликативные-операции)) |
|
||||
| `a % b` | Получение остатка от деления (см. раздел [2.3.8](#2-3-8-мультипликативные-операции)) |
|
||||
| `a + b` | Сложение (см. раздел [2.3.9](#2-3-9-аддитивные-операции)) |
|
||||
| `a - b` | Вычитание (см. раздел [2.3.9](#2-3-9-аддитивные-операции)) |
|
||||
| `a ~ b` | Конкатенация(см. раздел [2.3.9](#2-3-9-аддитивные-операции)) |
|
||||
| `a << b` | Сдвиг влево (см. раздел [2.3.10](#2-3-10-сдвиг)) |
|
||||
| `a >> b` | Сдвиг вправо (см. раздел [2.3.10](#2-3-10-сдвиг)) |
|
||||
| `a >>> b` | Беззнаковый сдвиг вправо (старший разряд сбрасывается независимо от типа и значения `a`) (см. раздел [2.3.10](#2-3-10-сдвиг)) |
|
||||
| `a in b` | Проверка на принадлежность для ассоциативных массивов (см. раздел [2.3.11](#2-3-11-выражения-in)) |
|
||||
| `a == b` | Проверка на равенство;<br>все операторы этой группы неассоциативны;<br>например, выражение `a == b == c` некорректно (см. раздел [2.3.12.1](#2-3-12-1-проверка-на-равенство)) |
|
||||
| `a != b` | Проверка на неравенство (см. раздел [2.3.12.1](#2-3-12-1-проверка-на-равенство)) |
|
||||
| `a is b` | Проверка на идентичность (`true`, если и только если `a` и `b` ссылаются на один и тот же объект) (см. раздел [2.3.12.1](#2-3-12-1-проверка-на-равенство)) |
|
||||
| `a !is b` | То же, что `!(a is b)` |
|
||||
| `a < b` | Меньше (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания)) |
|
||||
| `a <= b` | Меньше или равно (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания)) |
|
||||
| `a > b` | Больше (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания)) |
|
||||
| `a >= b` | Больше или равно (см. раздел [2.3.12.2](#2-3-12-2-сравнение-для-упорядочивания)) |
|
||||
| `a \| b` | Поразрядное **ИЛИ** (см. раздел [2.3.13](#2-3-13-поразрядные-или-исключающее-или-и-и)) |
|
||||
| `a ^ b` | Поразрядное **ИСКЛЮЧАЮЩЕЕ ИЛИ** (см. раздел [2.3.13](#2-3-13-поразрядные-или-исключающее-или-и-и)) |
|
||||
| `a & b` | Поразрядное **И** (см. раздел [2.3.13](#2-3-13-поразрядные-или-исключающее-или-и-и)) |
|
||||
| `a && b` | Логическое **И** (`b` может иметь тип `void`) (см. раздел [2.3.14](#2-3-14-логическое-и)) |
|
||||
| `a \|\| b` | Логическое **ИЛИ** (`b` может иметь тип `void`) (см. раздел [2.3.15](#2-3-15-логическое-или)) |
|
||||
| `a ? b : c` | Тернарная условная операция; если операнд `a` имеет ненулевое значение, то `b`, иначе `с` (см. раздел [2.3.16](#2-3-16-тернарная-условная-операция)) |
|
||||
| `a = b` | Присваивание;<br>все операторы присваивания этой группы ассоциативны справа;<br>например `a *= b += c` – то же, что и `a *= (b += c)` (см. раздел [2.3.17](#2-3-17-присваивание)) |
|
||||
| `a += b` | Сложение «на месте»;<br>выражения со всеми операторами вида `a ω= b`, работающими по принципу «вычислить и присвоить», вычисляются в следующем порядке:<br>**1)** `a` (должно быть l-значением),<br>**2)** `b` и<br>**3)** `al = al ω b`, где `al` – l-значение, получившееся в результате вычисления `a` |
|
||||
| `a -= b` | Вычитание «на месте» |
|
||||
| `a *= b` | Умножение «на месте» |
|
||||
| `a /= b` | Деление «на месте» |
|
||||
| `a %= b` | Получение остатка от деления «на месте» |
|
||||
| `a &= b` | Поразрядное **И** «на месте» |
|
||||
| `a \|= b` | Поразрядное **ИЛИ** «на месте» |
|
||||
| `a ^= b` | Поразрядное **ИСКЛЮЧАЮЩЕЕ ИЛИ** «на месте» |
|
||||
| `a ~= b` | Конкатенация «на месте» (присоединение `b` к `a`) |
|
||||
| `a <<= b` | Сдвиг влево «на месте» |
|
||||
| `a >>= b` | Сдвиг вправо «на месте» |
|
||||
| `a >>>= b` | Беззнаковый сдвиг вправо «на месте» |
|
||||
| `a, b` | Последовательность выражений; выражения вычисляются слева направо, результатом операции становится самое правое выражение (см. раздел [2.3.18](#2-3-18-выражения-с-запятой)) |
|
||||
|
||||
[В начало ⮍](#2-4-итоги-и-справочник) [Наверх ⮍](#2-основные-типы-данных-выражения)
|
||||
|
||||
|
|
|
@ -1097,39 +1097,39 @@ D предоставляет все ожидаемые обычные инстр
|
|||
|
||||
*Таблица 3.1. Справочник по инструкциям (`‹и›` – инструкция, `‹в›` – выражение, `‹o›` – объявление, `‹х›` – идентификатор)*
|
||||
|
||||
|Инструкция|Описание|
|
||||
|-|-|
|
||||
|`‹в›;`|Вычисляет `‹в›`. Ничего не изменяющие выражения, включающие лишь встроенные типы и операторы, запрещены (см. раздел [3.1](#3-1-инструкция-выражение))|
|
||||
|`{‹и1› ... ‹и2›}`|Выполняет инструкции от `‹и1›` до `‹и2›` по порядку, пока управление не будет явно передано в другую область видимости (например, инструкцией `return`) (см. раздел [3.2](#3-2-составная-инструкция))|
|
||||
|`asm ‹и›`|Машиннозависимый ассемблерный код (здесь `‹и›` обозначает ассемблерный код, а не инструкцию на языке D). В настоящее время поддерживается ассемблер x86 с единым синтаксисом для всех поддерживаемых операционных систем (см. раздел [3.15](#3-15-конструкция-asm))|
|
||||
|`break;`|Прерывает выполнение инструкции `switch`, `for`, `foreach`, `while` или `do-while` с переходом к инструкции, следующей сразу за ней (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break))|
|
||||
|`break ‹x›;`|Прерывает выполнение инструкции `switch`, `for`, `foreach`, `while` или `do-while`, имеющей метку `‹x›:`, с переходом к инструкции, следующей сразу за ней (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break))|
|
||||
|`continue;`|Начинает новую итерацию текущего (ближайшего к ней) цикла `for`, `foreach`, `while` или `do-while` с пропуском оставшейся части этого цикла (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break))|
|
||||
|`continue ‹x›;`|Начинает новую итерацию цикла `for`, `foreach`, `while` или `do-while`, снабженного меткой `‹x›:`, с пропуском оставшейся части этого цикла (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break))|
|
||||
|`do ‹и› while (‹в›);`|Выполняет `‹и›` один раз и продолжает ее выполнять, пока `‹в›` истинно (см. раздел [3.7.2](#3-7-2-инструкция-do-while-цикл-с-постусловием))|
|
||||
|`for (‹и1› ‹в1›; ‹в2›) ‹и2›`|Выполняет `‹и1›`, которая может быть инструкцией-выражением, определением значения или просто точкой с запятой, и пока `‹в1›` истинно, выполняет `‹и2›`, после чего вычисляет `‹в2›` (см. раздел [3.7.2](#3-7-3-инструкция-for-цикл-со-счетчиком))|
|
||||
|`foreach (‹x›; ‹в1› .. ‹в2›) ‹и›`|Выполняет `‹и›`, инициализируя переменную `‹x›` значением `‹в1›` и затем последовательно увеличивая ее на 1, пока `‹x› ‹ ‹в2›`. Цикл не выполняется, если `‹в1› ›= ‹в2›`. Как `‹в1›`, так и `‹в2›` вычисляются всего один раз (см. раздел [3.7.4](#3-7-4-инструкция-foreach-цикл-просмотра))|
|
||||
|`foreach (refопц ‹x›; ‹в›) ‹и›`|Выполняет `‹и›`, объявляя переменную `‹x›` и привязывая ее к каждому из элементов `‹в›` поочередно. Результатом вычисления `‹в›` должен быть массив или любой пользовательский тип-диапазон. Если присутствует ключевое слово `ref`, изменения `‹x›` будут отражаться и на просматриваемой сущности (см. раздел [3.7.5](#3-7-5-цикл-просмотра-для-работы-с-массивами))|
|
||||
|`foreach (‹x1›, refопц ‹x2›; ‹в›) ‹и›`|Аналогична предыдущей, но вводит дополнительное значение `‹x1›`. Если `‹в›` – это ассоциативный массив, то `‹x1›` привязывается к ключу, а `‹x2›` – к рассматриваемому значению. Иначе `‹x1›` привязывается к целому числу, показывающему количество проходов цикла (начиная с 0) (см. раздел [3.7.5](#3-7-5-цикл-просмотра-для-работы-с-массивами))|
|
||||
|`goto ‹x›;`|Выполняет переход к метке `‹x›`, которая должна быть определена в текущей функции как `‹x›:` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход))|
|
||||
|`goto case;`|Выполняет переход к следующей метке `case` текущей инструкции `switch` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход))|
|
||||
|`goto case ‹x›;`|Выполняет переход к метке `case ‹x›` текущей инструкции `switch` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход))|
|
||||
|`goto default;`|Выполняет переход к метке обработчика по умолчанию `default` текущей инструкции `switch` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход))|
|
||||
|`if (‹в›) ‹и›`|Выполняет `‹и›`, если `‹в›` ненулевое (см. раздел [3.3](#3-3-инструкция-if))|
|
||||
|`if (‹в›) ‹и1› else ‹и2›`|Выполняет `‹и1›`, если `‹в›` ненулевое, иначе выполняет `‹и2›`. Компонент `else`, расположенный в конце, относится к последней инструкции `if` или `static if` (см. раздел [3.3](#3-3-инструкция-if))|
|
||||
|`static if (‹в›)‹о/и›`|Вычисляет `‹в›` во время компиляции и, если `‹в›` ненулевое, компилирует объявление или инструкцию `‹о/и›`. Если объявление или инструкция `‹о/и›` заключены в `{` и `}`, то одна пара таких скобок срезается (см. раздел [3.4](#3-4-инструкция-static-if))|
|
||||
|`static if (‹в›)‹о/и1› else ‹о/и2›`|Аналогична предыдущей плюс в случае ложности `‹в›` компилирует `‹о/и2›`. Часть `else`, расположенная в конце, относится к последней инструкции `if` или `static if` (см. раздел [3.4](#3-4-инструкция-static-if))|
|
||||
|`return ‹в›опц;`|Возврат из текущей функции. Возвращаемое значение должно быть таким, чтобы его можно было неявно преобразовать к объявленному возвращаемому типу. `‹в›` может быть опущено, если возвращаемый тип функции – `void` (см. раздел [3.10](#3-10-инструкция-return))|
|
||||
|`scope(exit) ‹и›`|Выполняет `‹и›`, каким бы образом ни был осуществлен выход из текущего контекста (то есть с помощью `return`, из-за необработанной ошибки или по исключительной ситуации). Вложенные инструкции `scope` (в том числе с ключевыми словами `failure` и `success`) выполняются в порядке, обратном их определению в коде программы (см. раздел [3.13](#3-13-инструкция-scope))|
|
||||
|`scope(failure) ‹и›`|Выполняет `‹и›`, если выход из текущего контекста осуществлен по исключительной ситуации (см. раздел [3.13](#3-13-инструкция-scope))|
|
||||
|`scope(success) ‹и›`|Выполняет `‹и›` при нормальном выходе из текущего контекста (через `return` или по достижении конца контекста) (см. раздел [3.13](#3-13-инструкция-scope))|
|
||||
|`switch (‹в›) ‹и›`|Вычисляет `‹в›` и выполняет переход к метке `case`, соответствующей `‹в›` и расположенной внутри `‹и›` (см. раздел [3.5](#3-5-инструкция-switch))|
|
||||
|`final switch (‹в›) ‹и›`|Аналогична предыдущей, но работает только с перечисляемым и значениями и во время компиляции проверяет, обработаны ли все возможные значения с помощью меток `case` (см. раздел [3.6](#3-6-инструкция-final-switch))|
|
||||
|`synchronized (‹в1›, ‹в2›…)‹и›`|Выполняет `‹и›`, в то время как объекты, возвращаемые `‹в1›`, `‹в2›` и т.д., заблокированы. Выражения `‹вi›` должны возвращать объект типа `class` (см. раздел [3.14](#3-14-инструкция-synchronized))|
|
||||
|`throw (‹в›);`|Вычисляет `‹в›` и порождает соответствующее исключение с переходом в ближайший подходящий обработчик `catch`. `‹в›` должно иметь тип `Throwable` или наследующий от него (см. раздел [3.11](#3-11-обработка-исключительных-ситуаций))|
|
||||
|`try ‹и› catch(‹Т1› ‹x1›) ‹и1› ... catch(‹Тn› ‹xn›) ‹иn› finally ‹иf›`|Выполняет `‹и›`. Если при этом возникает исключение, пытается сопоставить его тип с типами `‹Т1›`, `...`, `‹Тn›` по порядку. Если `k`-е сопоставление оказалось удачным, то далее сопоставления не производятся и выполняется `‹иk›`. В любом случае (завершилось выполнение `‹и›` исключением или нет) перед выходом из `try` выполняется `‹иf›`. Все компоненты `catch` и `finally` (но не то и другое одновременно) могут быть опущены (см. раздел [3.11](#3-11-обработка-исключительных-ситуаций))|
|
||||
|`while (‹в›) ‹и›`|Выполняет `‹и›`, пока `‹в›` ненулевое (цикл не выполняется, если уже при первом вычислении `‹в›` оказывается нулевым) (см. раздел [3.13](#3-7-1-инструкция-while-цикл-с-предусловием))|
|
||||
|`with (‹в›) ‹и›`|Вычисляет `‹в›`, затем выполняет `‹и›`, как если бы она была членом типа `‹в›`: все используемые в `‹и›` идентификаторы сначала ищутся в пространстве имен, определенном `‹в›` (см. раздел [3.9](#3-9-инструкция-with))|
|
||||
| Инструкция | Описание |
|
||||
| --- | --- |
|
||||
| `‹в›;` | Вычисляет `‹в›`. Ничего не изменяющие выражения, включающие лишь встроенные типы и операторы, запрещены (см. раздел [3.1](#3-1-инструкция-выражение)) |
|
||||
| `{‹и1› ... ‹и2›}` | Выполняет инструкции от `‹и1›` до `‹и2›` по порядку, пока управление не будет явно передано в другую область видимости (например, инструкцией `return`) (см. раздел [3.2](#3-2-составная-инструкция)) |
|
||||
| `asm ‹и›` | Машиннозависимый ассемблерный код (здесь `‹и›` обозначает ассемблерный код, а не инструкцию на языке D). В настоящее время поддерживается ассемблер x86 с единым синтаксисом для всех поддерживаемых операционных систем (см. раздел [3.15](#3-15-конструкция-asm)) |
|
||||
| `break;` | Прерывает выполнение инструкции `switch`, `for`, `foreach`, `while` или `do-while` с переходом к инструкции, следующей сразу за ней (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break)) |
|
||||
| `break ‹x›;` | Прерывает выполнение инструкции `switch`, `for`, `foreach`, `while` или `do-while`, имеющей метку `‹x›:`, с переходом к инструкции, следующей сразу за ней (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break)) |
|
||||
| `continue;` | Начинает новую итерацию текущего (ближайшего к ней) цикла `for`, `foreach`, `while` или `do-while` с пропуском оставшейся части этого цикла (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break)) |
|
||||
| `continue ‹x›;` | Начинает новую итерацию цикла `for`, `foreach`, `while` или `do-while`, снабженного меткой `‹x›:`, с пропуском оставшейся части этого цикла (см. раздел [3.7.6](#3-7-6-инструкции-continue-и-break)) |
|
||||
| `do ‹и› while (‹в›);` | Выполняет `‹и›` один раз и продолжает ее выполнять, пока `‹в›` истинно (см. раздел [3.7.2](#3-7-2-инструкция-do-while-цикл-с-постусловием)) |
|
||||
| `for (‹и1› ‹в1›; ‹в2›) ‹и2›` | Выполняет `‹и1›`, которая может быть инструкцией-выражением, определением значения или просто точкой с запятой, и пока `‹в1›` истинно, выполняет `‹и2›`, после чего вычисляет `‹в2›` (см. раздел [3.7.2](#3-7-3-инструкция-for-цикл-со-счетчиком)) |
|
||||
| `foreach (‹x›; ‹в1› .. ‹в2›) ‹и›` | Выполняет `‹и›`, инициализируя переменную `‹x›` значением `‹в1›` и затем последовательно увеличивая ее на 1, пока `‹x› ‹ ‹в2›`. Цикл не выполняется, если `‹в1› ›= ‹в2›`. Как `‹в1›`, так и `‹в2›` вычисляются всего один раз (см. раздел [3.7.4](#3-7-4-инструкция-foreach-цикл-просмотра)) |
|
||||
| `foreach (refопц ‹x›; ‹в›) ‹и›` | Выполняет `‹и›`, объявляя переменную `‹x›` и привязывая ее к каждому из элементов `‹в›` поочередно. Результатом вычисления `‹в›` должен быть массив или любой пользовательский тип-диапазон. Если присутствует ключевое слово `ref`, изменения `‹x›` будут отражаться и на просматриваемой сущности (см. раздел [3.7.5](#3-7-5-цикл-просмотра-для-работы-с-массивами)) |
|
||||
| `foreach (‹x1›, refопц ‹x2›; ‹в›) ‹и›` | Аналогична предыдущей, но вводит дополнительное значение `‹x1›`. Если `‹в›` – это ассоциативный массив, то `‹x1›` привязывается к ключу, а `‹x2›` – к рассматриваемому значению. Иначе `‹x1›` привязывается к целому числу, показывающему количество проходов цикла (начиная с 0) (см. раздел [3.7.5](#3-7-5-цикл-просмотра-для-работы-с-массивами)) |
|
||||
| `goto ‹x›;` | Выполняет переход к метке `‹x›`, которая должна быть определена в текущей функции как `‹x›:` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход)) |
|
||||
| `goto case;` | Выполняет переход к следующей метке `case` текущей инструкции `switch` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход)) |
|
||||
| `goto case ‹x›;` | Выполняет переход к метке `case ‹x›` текущей инструкции `switch` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход)) |
|
||||
| `goto default;` | Выполняет переход к метке обработчика по умолчанию `default` текущей инструкции `switch` (см. раздел [3.8](#3-8-инструкция-goto-безусловный-переход)) |
|
||||
| `if (‹в›) ‹и›` | Выполняет `‹и›`, если `‹в›` ненулевое (см. раздел [3.3](#3-3-инструкция-if)) |
|
||||
| `if (‹в›) ‹и1› else ‹и2›` | Выполняет `‹и1›`, если `‹в›` ненулевое, иначе выполняет `‹и2›`. Компонент `else`, расположенный в конце, относится к последней инструкции `if` или `static if` (см. раздел [3.3](#3-3-инструкция-if)) |
|
||||
| `static if (‹в›)‹о/и›` | Вычисляет `‹в›` во время компиляции и, если `‹в›` ненулевое, компилирует объявление или инструкцию `‹о/и›`. Если объявление или инструкция `‹о/и›` заключены в `{` и `}`, то одна пара таких скобок срезается (см. раздел [3.4](#3-4-инструкция-static-if)) |
|
||||
| `static if (‹в›)‹о/и1› else ‹о/и2›` | Аналогична предыдущей плюс в случае ложности `‹в›` компилирует `‹о/и2›`. Часть `else`, расположенная в конце, относится к последней инструкции `if` или `static if` (см. раздел [3.4](#3-4-инструкция-static-if)) |
|
||||
| `return ‹в›опц;` | Возврат из текущей функции. Возвращаемое значение должно быть таким, чтобы его можно было неявно преобразовать к объявленному возвращаемому типу. `‹в›` может быть опущено, если возвращаемый тип функции – `void` (см. раздел [3.10](#3-10-инструкция-return)) |
|
||||
| `scope(exit) ‹и›` | Выполняет `‹и›`, каким бы образом ни был осуществлен выход из текущего контекста (то есть с помощью `return`, из-за необработанной ошибки или по исключительной ситуации). Вложенные инструкции `scope` (в том числе с ключевыми словами `failure` и `success`) выполняются в порядке, обратном их определению в коде программы (см. раздел [3.13](#3-13-инструкция-scope)) |
|
||||
| `scope(failure) ‹и›` | Выполняет `‹и›`, если выход из текущего контекста осуществлен по исключительной ситуации (см. раздел [3.13](#3-13-инструкция-scope)) |
|
||||
| `scope(success) ‹и›` | Выполняет `‹и›` при нормальном выходе из текущего контекста (через `return` или по достижении конца контекста) (см. раздел [3.13](#3-13-инструкция-scope)) |
|
||||
| `switch (‹в›) ‹и›` | Вычисляет `‹в›` и выполняет переход к метке `case`, соответствующей `‹в›` и расположенной внутри `‹и›` (см. раздел [3.5](#3-5-инструкция-switch)) |
|
||||
| `final switch (‹в›) ‹и›` | Аналогична предыдущей, но работает только с перечисляемым и значениями и во время компиляции проверяет, обработаны ли все возможные значения с помощью меток `case` (см. раздел [3.6](#3-6-инструкция-final-switch)) |
|
||||
| `synchronized (‹в1›, ‹в2›…)‹и›` | Выполняет `‹и›`, в то время как объекты, возвращаемые `‹в1›`, `‹в2›` и т.д., заблокированы. Выражения `‹вi›` должны возвращать объект типа `class` (см. раздел [3.14](#3-14-инструкция-synchronized)) |
|
||||
| `throw (‹в›);` | Вычисляет `‹в›` и порождает соответствующее исключение с переходом в ближайший подходящий обработчик `catch`. `‹в›` должно иметь тип `Throwable` или наследующий от него (см. раздел [3.11](#3-11-обработка-исключительных-ситуаций)) |
|
||||
| `try ‹и› catch(‹Т1› ‹x1›) ‹и1› ... catch(‹Тn› ‹xn›) ‹иn› finally ‹иf›` | Выполняет `‹и›`. Если при этом возникает исключение, пытается сопоставить его тип с типами `‹Т1›`, `...`, `‹Тn›` по порядку. Если `k`-е сопоставление оказалось удачным, то далее сопоставления не производятся и выполняется `‹иk›`. В любом случае (завершилось выполнение `‹и›` исключением или нет) перед выходом из `try` выполняется `‹иf›`. Все компоненты `catch` и `finally` (но не то и другое одновременно) могут быть опущены (см. раздел [3.11](#3-11-обработка-исключительных-ситуаций)) |
|
||||
| `while (‹в›) ‹и›` | Выполняет `‹и›`, пока `‹в›` ненулевое (цикл не выполняется, если уже при первом вычислении `‹в›` оказывается нулевым) (см. раздел [3.13](#3-7-1-инструкция-while-цикл-с-предусловием)) |
|
||||
| `with (‹в›) ‹и›` | Вычисляет `‹в›`, затем выполняет `‹и›`, как если бы она была членом типа `‹в›`: все используемые в `‹и›` идентификаторы сначала ищутся в пространстве имен, определенном `‹в›` (см. раздел [3.9](#3-9-инструкция-with)) |
|
||||
|
||||
[В начало ⮍](#3-16-итоги-и-справочник) [Наверх ⮍](#3-инструкции)
|
||||
|
||||
|
|
|
@ -201,10 +201,10 @@ D различает «безопасные» (safe) и «системные» (
|
|||
|
||||
*Таблица 4.1. Проверка границ в зависимости от вида модуля и режима сборки*
|
||||
|
||||
||Безопасный модуль|Системный модуль|
|
||||
|-|:-:|:-:|
|
||||
|Промежуточная сборка|✓|✓|
|
||||
|Итоговая сборка (флаг `-release` для компилятора `dmd`)|✓|☠|
|
||||
| | Безопасный модуль | Системный модуль |
|
||||
| --- | :-: | :-: |
|
||||
| Промежуточная сборка | ✓ | ✓ |
|
||||
| Итоговая сборка (флаг `-release` для компилятора `dmd`) | ✓ | ☠ |
|
||||
|
||||
Вас предупредили.
|
||||
|
||||
|
@ -263,16 +263,16 @@ auto a = [1, 5, 2, 3, 6];
|
|||
|
||||
Инициализация массива другим массивом (`auto b = a`), равно как и присваивание одного массива другому (`int[] b; … b = a;`) не влечет скрытого автоматического копирования данных. Как показано на рис. 4.2, эти действия просто заставляют `b` ссылаться на ту же область памяти, что и `a`.
|
||||
|
||||

|
||||
|
||||
***Рис. 4.2.*** *При выполнении инструкции `auto b = a;` содержимое a не копируется: вместо этого создается объект типа «массив», который ссылается на те же данные*
|
||||
|
||||
Более того, получение среза массива `b` сокращает область памяти, «видимую» `b`, также без всякого копирования `b`. При условии что исходное состояние массива задано на рис. 4.2, выполнение инструкции
|
||||
|
||||
```d
|
||||
b = b[1 .. $ - 2];
|
||||
```
|
||||
|
||||

|
||||
|
||||
***Рис. 4.2.*** *При выполнении инструкции `auto b = a;` содержимое a не копируется: вместо этого создается объект типа «массив», который ссылается на те же данные*
|
||||
|
||||
приведет лишь к сокращению диапазона, доступного `b`, без какого-либо копирования данных (рис. 4.3).
|
||||
|
||||

|
||||
|
@ -769,7 +769,9 @@ double[5] e = a ~ d; // Все в порядке, явный запрос ма
|
|||
Поскольку запись `T[]` означает динамический массив элементов типа `T`, а `T[]`, в свою очередь, – тоже тип, легко сделать вывод, что `T[][]` – это массив элементов типа `T[]`, то есть массив массивов элементов типа `T`. Каждый элемент «внешнего» массива – это, в свою очередь, тоже массив, предоставляющий обычную функциональность, присущую массивам. Рассмотрим `T[][]` на практике:
|
||||
|
||||
```d
|
||||
auto array = new double[][5]; // Массив из пяти массивов, содержащих элементы типа double, первоначально каждый из них – null
|
||||
auto array = new double[][5]; // Массив из пяти массивов, содержащих элементы типа double,
|
||||
// первоначально каждый из них – null
|
||||
|
||||
// Сделать треугольную матрицу
|
||||
foreach (i, ref e; array)
|
||||
{
|
||||
|
@ -1049,14 +1051,14 @@ foreach (k; gammaFunc.byKey())
|
|||
|
||||
*Таблица 4.2. Битовые представления UTF-8. Длина представления определяется по контрольным битам, что позволяет выполнять синхронизацию посреди потока, восстановление после ошибок и просмотр строки в обратном направлении*
|
||||
|
||||
|Кодовая точка (в шестнадцатиричном представлении)|Бинарное представление|
|
||||
|-|-|
|
||||
|`00000000–0000007F`|`0xxxxxxx`|
|
||||
|`00000080–000007FF`|`110xxxxx 10xxxxxx`|
|
||||
|`00000800–0000FFFF`|`1110xxxx 10xxxxxx 10xxxxxx`|
|
||||
|`00010000–001FFFFF`|`11110xxx 10xxxxxx 10xxxxxx 10xxxxxx`|
|
||||
|`00200000–03FFFFFF`|`111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx`|
|
||||
|`04000000–7FFFFFFF`|`1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx`|
|
||||
| Кодовая точка (в шестнадцатиричном представлении) | Бинарное представление |
|
||||
| --- | --- |
|
||||
| `00000000–0000007F` | `0xxxxxxx` |
|
||||
| `00000080–000007FF` | `110xxxxx 10xxxxxx` |
|
||||
| `00000800–0000FFFF` | `1110xxxx 10xxxxxx 10xxxxxx` |
|
||||
| `00010000–001FFFFF` | `11110xxx 10xxxxxx 10xxxxxx 10xxxxxx` |
|
||||
| `00200000–03FFFFFF` | `111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx` |
|
||||
| `04000000–7FFFFFFF` | `1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx` |
|
||||
|
||||
Поскольку на сегодня верхней границей диапазона кодовых точек Юникод является число `0x10FFFF`, две последние последовательности зарезервированы для использования в будущем; в настоящее время корректны только четырехбайтные представления.
|
||||
|
||||
|
@ -1286,68 +1288,68 @@ y += 100; // Хм...
|
|||
|
||||
*Таблица 4.3. Операции над динамическими массивами (`a` и `b` – два значения типа `T[]`; `t`, `t1`, ..., `tk` – значения типа `T`; `n` – значение, приводимое к типу `размер_t`)*
|
||||
|
||||
|Выражение|Тип|Описание|
|
||||
|-|-|-|
|
||||
|`new T[n]`|`T[]`|Создает массив (см. раздел [4.1](#4-1-динамические-массивы))|
|
||||
|`[t1,t2, ..., tk]`|`T[]`|Литерал массива; `T` определяется по типу `t1` (см. разделы [2.2.6](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-2-6-литералы-массивов-и-ассоциативных-массивов) и [4.1](#4-1-динамические-массивы))|
|
||||
|`a = b`|`T[]`|Присваивает один массив другому (см. раздел [4.1.4](#4-1-4-копирование))|
|
||||
|`a[‹в›]`|`ref T`|Предоставляет доступ к элементу по индексу (символ `$` в выражении `‹в›` заменяется на `a.length`, `‹в›` должно быть приводимым к типу `размер_t`; кроме того, должно соблюдаться условие `‹в› < a.length`) (см. раздел [4.1](#4-1-динамические-массивы))|
|
||||
|`a[‹в1› .. ‹в2›]`|`T[]`|Получает срез массива `a` (знак `$` в `‹в1›` и `‹в2›` заменяется на `a.length`, `‹в1›` и `‹в2›` должны быть приводимыми к типу `размер_t`, также должно соблюдаться условие `‹в1› <= ‹в2› && ‹в2› <= a.length`) (см. раздел [4.1.3](#4-1-3-срезы))|
|
||||
|`a[]`|`T[]`|Поэлементная операция (см. раздел [4.1.7](#4-1-7-поэлементные-операции)) или альтернативное написание выражения `a[0 .. $]`, возвращающего содержимое всего массива|
|
||||
|`a.dup`|`T[]`|Получает дубликат массива (см. раздел [4.1](#4-1-динамические-массивы))|
|
||||
|`a.length`|`размер_t`|Читает длину массива (см. раздел [4.1.10](#4-1-10-присваивание-значения-свойству-length))|
|
||||
|`a.length = n`|`размер_t`|Изменяет длину массива (см. раздел [4.1.1](#4-1-1-длина))|
|
||||
|`a is b`|`bool`|Проверяет, идентичны ли массивы друг другу (см. разделы [4.1.5](#4-1-5-проверка-на-равенство) и [2.3.4.3](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-4-3-выражения-is))|
|
||||
|`a !is b`|`bool`|То же, что `!(a is b)`|
|
||||
|`a == b`|`bool`|Поэлементно сравнивает массивы на равенство (см. раздел [4.1.5](#4-1-5-проверка-на-равенство))|
|
||||
|`a != b`|`bool`|То же, что `!(a == b)`|
|
||||
|`a ~ t`|`T[]`|Конкатенирует массив и отдельное значение (см. раздел [4.1.6](#4-1-6-конкатенация))|
|
||||
|`t ~ a`|`T[]`|Конкатенирует отдельное значение и массив (см. раздел [4.1.6](#4-1-6-конкатенация))|
|
||||
|`a ~ b`|`T[]`|Конкатенирует два массива (см. раздел [4.1.6](#4-1-6-конкатенация))|
|
||||
|`a ~= t`|`T[]`|Присоединяет элемент к массиву (см. раздел [4.1.6](#4-1-6-конкатенация))|
|
||||
|`a ~= b`|`T[]`|Присоединяет один массив к другому (см. раздел [4.1.6](#4-1-6-конкатенация))|
|
||||
|`a.ptr`|`T*`|Возвращает адрес первого элемента массива `a` (небезопасная операция) (см. раздел [4.6](#4-6-опасный-собрат-массива-указатель))|
|
||||
| Выражение | Тип | Описание |
|
||||
| --- | --- | --- |
|
||||
| `new T[n]` | `T[]` | Создает массив (см. раздел [4.1](#4-1-динамические-массивы)) |
|
||||
| `[t1,t2, ..., tk]` | `T[]` | Литерал массива; `T` определяется по типу `t1` (см. разделы [2.2.6](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-2-6-литералы-массивов-и-ассоциативных-массивов) и [4.1](#4-1-динамические-массивы)) |
|
||||
| `a = b` | `T[]` | Присваивает один массив другому (см. раздел [4.1.4](#4-1-4-копирование)) |
|
||||
| `a[‹в›]` | `ref T` | Предоставляет доступ к элементу по индексу (символ `$` в выражении `‹в›` заменяется на `a.length`, `‹в›` должно быть приводимым к типу `размер_t`; кроме того, должно соблюдаться условие `‹в› < a.length`) (см. раздел [4.1](#4-1-динамические-массивы)) |
|
||||
| `a[‹в1› .. ‹в2›]` | `T[]` | Получает срез массива `a` (знак `$` в `‹в1›` и `‹в2›` заменяется на `a.length`, `‹в1›` и `‹в2›` должны быть приводимыми к типу `размер_t`, также должно соблюдаться условие `‹в1› <= ‹в2› && ‹в2› <= a.length`) (см. раздел [4.1.3](#4-1-3-срезы)) |
|
||||
| `a[]` | `T[]` | Поэлементная операция (см. раздел [4.1.7](#4-1-7-поэлементные-операции)) или альтернативное написание выражения `a[0 .. $]`, возвращающего содержимое всего массива |
|
||||
| `a.dup` | `T[]` | Получает дубликат массива (см. раздел [4.1](#4-1-динамические-массивы)) |
|
||||
| `a.length` | `размер_t` | Читает длину массива (см. раздел [4.1.10](#4-1-10-присваивание-значения-свойству-length)) |
|
||||
| `a.length = n` | `размер_t` | Изменяет длину массива (см. раздел [4.1.1](#4-1-1-длина)) |
|
||||
| `a is b` | `bool` | Проверяет, идентичны ли массивы друг другу (см. разделы [4.1.5](#4-1-5-проверка-на-равенство) и [2.3.4.3](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-4-3-выражения-is)) |
|
||||
| `a !is b` | `bool` | То же, что `!(a is b)` |
|
||||
| `a == b` | `bool` | Поэлементно сравнивает массивы на равенство (см. раздел [4.1.5](#4-1-5-проверка-на-равенство)) |
|
||||
| `a != b` | `bool` | То же, что `!(a == b)` |
|
||||
| `a ~ t` | `T[]` | Конкатенирует массив и отдельное значение (см. раздел [4.1.6](#4-1-6-конкатенация)) |
|
||||
| `t ~ a` | `T[]` | Конкатенирует отдельное значение и массив (см. раздел [4.1.6](#4-1-6-конкатенация)) |
|
||||
| `a ~ b` | `T[]` | Конкатенирует два массива (см. раздел [4.1.6](#4-1-6-конкатенация)) |
|
||||
| `a ~= t` | `T[]` | Присоединяет элемент к массиву (см. раздел [4.1.6](#4-1-6-конкатенация)) |
|
||||
| `a ~= b` | `T[]` | Присоединяет один массив к другому (см. раздел [4.1.6](#4-1-6-конкатенация)) |
|
||||
| `a.ptr` | `T*` | Возвращает адрес первого элемента массива `a` (небезопасная операция) (см. раздел [4.6](#4-6-опасный-собрат-массива-указатель)) |
|
||||
|
||||
*Таблица 4.4. Операции над массивами фиксированной длины (`a` и `b` – два значения типа `T[]`; `t`, `t1`, ..., `tk` – значения типа `T`; `n` – значение, приводимое к типу `размер_t`)*
|
||||
|
||||
|Выражение|Тип|Описание|
|
||||
|-|-|-|
|
||||
|`[t1, ..., tk]`|`T[k]`|Литерал массива, но только если тип `T[k]` запрошен явно; `T` определяется по типу `t1` (см. разделы [2.2.6](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-2-6-литералы-массивов-и-ассоциативных-массивов) и [4.1](#4-1-динамические-массивы))|
|
||||
|`a = b`|`ref T[n]`|Копирует содержимое одного массива в другой (см. раздел [4.2.4](#4-2-4-копирование-и-неявные-преобразования))|
|
||||
|`a[‹в›]`|`ref T`|Предоставляет доступ к элементу по индексу (символ `$` в `‹в›` заменяется на `a.length`, `‹в›` должно быть приводимым к типу `размер_t`; кроме того, должно соблюдаться условие `‹в› < a.length`) (см. раздел [4.1](#4-1-динамические-массивы))|
|
||||
|`a[‹в1› .. ‹в2›]`|`T[]/T[k]`|Получает срез массива `a` (символ `$` в `‹в1›` и `‹в2›` заменяется на `a.length`, `‹в1›` и `‹в2›` должны быть приводимыми к типу `размер_t`, также должно соблюдаться условие `‹в1› <= ‹в2› && ‹в2› <= a.length`) (см. раздел [4.2.3](#4-2-3-получение-срезов))|
|
||||
|`a[]`|`T[]`|Поэлементная операция (см. раздел [4.1.7](#4-1-7-поэлементные-операции)) или приведение `a` (массива фиксированной длины) к типу динамического массива, то же, что и `a[0 .. $]`|
|
||||
|`a.dup`|`T[]`|Получает дубликат массива (см. раздел [4.2.4](#4-2-4-копирование-и-неявные-преобразования))|
|
||||
|`a.length`|`размер_t`|Читает длину массива (см. раздел [4.2.1](#4-2-1-длина))|
|
||||
|`a is b`|`bool`|Проверяет, идентичны ли массивы друг другу (см. разделы [4.2.5](#4-2-5-проверка-на-равенство) и [2.3.4.3](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-4-3-выражения-is))|
|
||||
|`a !is b`|`bool`|То же, что и `!(a is b)`|
|
||||
|`a == b`|`bool`|Поэлементно сравнивает массивы на равенство (см. разделы [4.2.5](#4-2-5-проверка-на-равенство) и [2.3.12](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-12-сравнение))|
|
||||
|`a != b`|`bool`|То же, что и `!(a == b)`|
|
||||
|`a ~ t`|`T[]`|Конкатенирует массив и отдельное значение (см. раздел [4.2.6](#4-2-6-конкатенация))|
|
||||
|`t ~ a`|`T[]`|Конкатенирует отдельное значение и массив (см. раздел [4.2.6](#4-2-6-конкатенация))|
|
||||
|`a ~ b`|`T[]`|Конкатенирует два массива (см. раздел [4.2.6](#4-2-6-конкатенация))|
|
||||
|`a.ptr`|`T*`|Возвращает адрес первого элемента массива `a` (небезопасная операция)|
|
||||
| Выражение | Тип | Описание |
|
||||
| --- | --- | --- |
|
||||
| `[t1, ..., tk]` | `T[k]` | Литерал массива, но только если тип `T[k]` запрошен явно; `T` определяется по типу `t1` (см. разделы [2.2.6](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-2-6-литералы-массивов-и-ассоциативных-массивов) и [4.1](#4-1-динамические-массивы)) |
|
||||
| `a = b` | `ref T[n]` | Копирует содержимое одного массива в другой (см. раздел [4.2.4](#4-2-4-копирование-и-неявные-преобразования)) |
|
||||
| `a[‹в›]` | `ref T` | Предоставляет доступ к элементу по индексу (символ `$` в `‹в›` заменяется на `a.length`, `‹в›` должно быть приводимым к типу `размер_t`; кроме того, должно соблюдаться условие `‹в› < a.length`) (см. раздел [4.1](#4-1-динамические-массивы)) |
|
||||
| `a[‹в1› .. ‹в2›]` | `T[]/T[k]` | Получает срез массива `a` (символ `$` в `‹в1›` и `‹в2›` заменяется на `a.length`, `‹в1›` и `‹в2›` должны быть приводимыми к типу `размер_t`, также должно соблюдаться условие `‹в1› <= ‹в2› && ‹в2› <= a.length`) (см. раздел [4.2.3](#4-2-3-получение-срезов)) |
|
||||
| `a[]` | `T[]` | Поэлементная операция (см. раздел [4.1.7](#4-1-7-поэлементные-операции)) или приведение `a` (массива фиксированной длины) к типу динамического массива, то же, что и `a[0 .. $]` |
|
||||
| `a.dup` | `T[]` | Получает дубликат массива (см. раздел [4.2.4](#4-2-4-копирование-и-неявные-преобразования)) |
|
||||
| `a.length` | `размер_t` | Читает длину массива (см. раздел [4.2.1](#4-2-1-длина)) |
|
||||
| `a is b` | `bool` | Проверяет, идентичны ли массивы друг другу (см. разделы [4.2.5](#4-2-5-проверка-на-равенство) и [2.3.4.3](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-4-3-выражения-is)) |
|
||||
| `a !is b` | `bool` | То же, что и `!(a is b)` |
|
||||
| `a == b` | `bool` | Поэлементно сравнивает массивы на равенство (см. разделы [4.2.5](#4-2-5-проверка-на-равенство) и [2.3.12](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-12-сравнение)) |
|
||||
| `a != b` | `bool` | То же, что и `!(a == b)` |
|
||||
| `a ~ t` | `T[]` | Конкатенирует массив и отдельное значение (см. раздел [4.2.6](#4-2-6-конкатенация)) |
|
||||
| `t ~ a` | `T[]` | Конкатенирует отдельное значение и массив (см. раздел [4.2.6](#4-2-6-конкатенация)) |
|
||||
| `a ~ b` | `T[]` | Конкатенирует два массива (см. раздел [4.2.6](#4-2-6-конкатенация)) |
|
||||
| `a.ptr` | `T*` | Возвращает адрес первого элемента массива `a` (небезопасная операция) |
|
||||
|
||||
*Таблица 4.5. Операции над ассоциативными массивами (`a` и `b` – два значения типа `V[K]`; `k`, `k1`, ..., `ki` – значения типа `K`; `v`, `v1`, ..., `vk` – значения типа `V`)*
|
||||
|
||||
|Выражение|Тип|Описание|
|
||||
|-|-|-|
|
||||
|`[t1:v1, ..., ti:vi]`|`V[K]`|Литерал ассоциативного массива; `K` определяется по типу `k1`, а `V` – по типу `v1` (см. разделы [2.2.6](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-2-6-литералы-массивов-и-ассоциативных-массивов) и [4.4](#4-4-ассоциативные-массивы))|
|
||||
|`a = b`|`V[K]`|Присваивает ассоциативный массив `b` переменной a типа «ассоциативный массив» (см. раздел [4.4.3](#4-4-3-копирование))|
|
||||
|`a[k]`|`V`|Предоставляет доступ к элементу по индексу (если ключ `k` не найден, возникает исключение) (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек))|
|
||||
|`a[k] = v`|`V`|Ставит в соответствие ключу `k` значение `v` (переопределяет предыдущее соответствие, если оно уже было назначено) (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек))|
|
||||
|`k in a`|`V*`|Ищет `k` в `a`, возвращает `null`, если не находит, иначе – указатель на значение, ассоциированное с `k` (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек))|
|
||||
|`k !in a`|`bool`|То же, что и `!(k in a)`|
|
||||
|`a.length`|`размер_t`|Читает значение, соответствующее числу элементов в `a` (см. раздел [4.4.1](#4-4-1-длина))|
|
||||
|`a is b`|`bool`|Проверяет, идентичны ли массивы друг другу (см. разделы [4.4.4](#4-4-4-проверка-на-равенство) и [2.3.4.3](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-4-3-выражения-is))|
|
||||
|`a !is b`|`bool`|То же, что и `!(a is b)`|
|
||||
|`a == b`|`bool`|Поэлементно сравнивает массивы на равенство (см. разделы [4.4.4](#4-4-4-проверка-на-равенство) и [2.3.12](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-12-сравнение))|
|
||||
|`a != b`|`bool`|То же, что и `!(a == b)`|
|
||||
|`a.remove(k)`|`bool`|Удаляет пару с ключом `k`, если такая есть; возвращает `true`, если и только если ключ `k` присутствовал в `a` (см. раздел [4.4.5](#4-4-5-удаление-элементов))|
|
||||
|`a.dup`|`V[K]`|Создает дубликат ассоциативного массива `a` (см. раздел [4.4.3](#4-4-3-копирование))|
|
||||
|`a.get(k, v)`|`V`|Возвращает значение из `a`, соответствующее ключу `k`; по умолчанию возвращается значение `v` (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек))|
|
||||
|`a.byKey()`|`int delegate(int delegate(ref K))`|Возвращает делегат, пригодный для использования в цикле `foreach` для итерации по ключам|
|
||||
|`a.byValue()`|`int delegate(int delegate(ref V))`|Возвращает делегат, пригодный для использования в цикле `foreach` для итерации по значениям|
|
||||
| Выражение | Тип | Описание |
|
||||
| --- | --- | --- |
|
||||
| `[t1:v1, ..., ti:vi]` | `V[K]` | Литерал ассоциативного массива; `K` определяется по типу `k1`, а `V` – по типу `v1` (см. разделы [2.2.6](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-2-6-литералы-массивов-и-ассоциативных-массивов) и [4.4](#4-4-ассоциативные-массивы)) |
|
||||
| `a = b` | `V[K]` | Присваивает ассоциативный массив `b` переменной a типа «ассоциативный массив» (см. раздел [4.4.3](#4-4-3-копирование)) |
|
||||
| `a[k]` | `V` | Предоставляет доступ к элементу по индексу (если ключ `k` не найден, возникает исключение) (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек)) |
|
||||
| `a[k] = v` | `V` | Ставит в соответствие ключу `k` значение `v` (переопределяет предыдущее соответствие, если оно уже было назначено) (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек)) |
|
||||
| `k in a` | `V*` | Ищет `k` в `a`, возвращает `null`, если не находит, иначе – указатель на значение, ассоциированное с `k` (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек)) |
|
||||
| `k !in a` | `bool` | То же, что и `!(k in a)` |
|
||||
| `a.length` | `размер_t` | Читает значение, соответствующее числу элементов в `a` (см. раздел [4.4.1](#4-4-1-длина)) |
|
||||
| `a is b` | `bool` | Проверяет, идентичны ли массивы друг другу (см. разделы [4.4.4](#4-4-4-проверка-на-равенство) и [2.3.4.3](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-4-3-выражения-is)) |
|
||||
| `a !is b` | `bool` | То же, что и `!(a is b)` |
|
||||
| `a == b` | `bool` | Поэлементно сравнивает массивы на равенство (см. разделы [4.4.4](#4-4-4-проверка-на-равенство) и [2.3.12](../02-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#2-3-12-сравнение)) |
|
||||
| `a != b` | `bool` | То же, что и `!(a == b)` |
|
||||
| `a.remove(k)` | `bool` | Удаляет пару с ключом `k`, если такая есть; возвращает `true`, если и только если ключ `k` присутствовал в `a` (см. раздел [4.4.5](#4-4-5-удаление-элементов)) |
|
||||
| `a.dup` | `V[K]` | Создает дубликат ассоциативного массива `a` (см. раздел [4.4.3](#4-4-3-копирование)) |
|
||||
| `a.get(k, v)` | `V` | Возвращает значение из `a`, соответствующее ключу `k`; по умолчанию возвращается значение `v` (см. раздел [4.4.2](#4-4-2-чтение-и-запись-ячеек)) |
|
||||
| `a.byKey()` | `int delegate(int delegate(ref K))` | Возвращает делегат, пригодный для использования в цикле `foreach` для итерации по ключам |
|
||||
| `a.byValue()` | `int delegate(int delegate(ref V))` | Возвращает делегат, пригодный для использования в цикле `foreach` для итерации по значениям |
|
||||
|
||||
[В начало ⮍](#4-7-итоги-и-справочник) [Наверх ⮍](#4-массивы-ассоциативные-массивы-и-строки)
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ void fun(in int[][] data)
|
|||
|
||||
### 5.2.3. Выходные параметры (с ключевым словом out)
|
||||
|
||||
Иногда параметры передаются по ссылке только для того, чтобы функция с их помощью что-то вернула. В таких случаях можно воспользоваться классом памяти `out`, напоминающим `ref`, – разница лишь в том, что перед входом в функцию `out` инициализирует свой аргумент значением по умолчанию (соответствующим типу аргумента):
|
||||
Иногда параметры передаются по ссылке только для того, чтобы функция с их помощью что-то вернула. В таких случаях можно воспользоваться классом памяти `out`, напоминающим `ref` – разница лишь в том, что перед входом в функцию `out` инициализирует свой аргумент значением по умолчанию (соответствующим типу аргумента):
|
||||
|
||||
```d
|
||||
// Вычисляет частное и остаток от деления для аргументов a и b.
|
||||
|
@ -258,7 +258,8 @@ void log(string message)
|
|||
writeln(message);
|
||||
}
|
||||
...
|
||||
int result = foo(); log("foo() returned " ~ to!string(result));
|
||||
int result = foo();
|
||||
log("foo() returned " ~ to!string(result));
|
||||
```
|
||||
|
||||
Как видим, вычислять выражение `"foo() returned " ~ to!string(result)` нужно, только если переменная `verbose` имеет значение `true`. При этом выражение, передаваемое этой функции в качестве аргумента, будет вычислено в любом случае. В данном примере это конкатенация двух строк, которая потребует выделения памяти и копирования в нее содержимого каждой из них. И все это для того, чтобы узнать, что переменная `verbose` имеет значение `false` и значение аргумента никому не нужно! Можно было бы передавать вместо строки делегат, возвращающий строку (делегаты описаны в разделе 5.6.1):
|
||||
|
@ -269,7 +270,8 @@ void log(string delegate() message)
|
|||
if (verbose)
|
||||
writeln(message());
|
||||
}
|
||||
...log({return "foo() returned " ~ to!string(result);});
|
||||
...
|
||||
log({return "foo() returned " ~ to!string(result);});
|
||||
```
|
||||
|
||||
В этом случае аргумент будет вычислен, только если он действительно нужен, но такая форма слишком громоздка. Поэтому D вводит такое понятие, как «ленивые» аргументы. Такие аргументы объявляются с атрибутом `lazy`, выглядят как обычные аргументы, но вычисляются только тогда, когда требуется их значение.
|
||||
|
@ -869,7 +871,7 @@ T[] find(T)(T[] haystack, T needle)
|
|||
2. `haystack[0]` осуществляет доступ к первому элементу `haystack`.
|
||||
3. `haystack = haystack[1 .. $]` исключает из рассмотрения первый элемент `haystack`.
|
||||
|
||||
Конкретный способ, каким массивы реализуют эти операции, непросто распространить на другие контейнеры. Например, проверять с помощью выражения `haystack.length > 0`, есть ли в односвязном списке элементы, – подход, достойный премии Дарвина[^9]. Если не обеспечено постоянное кэширование длины списка (что по многим причинам весьма проблематично), то для вычисления длины списка таким способом потребуется время, пропорциональное самой длине списка, а быстрое обращение к началу списка занимает всего лишь несколько машинных инструкций. Применить к спискам индексацию – столь же проигрышная идея. Так что выделим сущность рассмотренных операций, представим полученный результат в виде трех именованных функций и оставим их реализацию типу `haystack`. Примерный синтаксис базовых операций, необходимых для реализации алгоритма линейного поиска:
|
||||
Конкретный способ, каким массивы реализуют эти операции, непросто распространить на другие контейнеры. Например, проверять с помощью выражения `haystack.length > 0`, есть ли в односвязном списке элементы – подход, достойный премии Дарвина[^9]. Если не обеспечено постоянное кэширование длины списка (что по многим причинам весьма проблематично), то для вычисления длины списка таким способом потребуется время, пропорциональное самой длине списка, а быстрое обращение к началу списка занимает всего лишь несколько машинных инструкций. Применить к спискам индексацию – столь же проигрышная идея. Так что выделим сущность рассмотренных операций, представим полученный результат в виде трех именованных функций и оставим их реализацию типу `haystack`. Примерный синтаксис базовых операций, необходимых для реализации алгоритма линейного поиска:
|
||||
|
||||
1. `haystack.empty` – для проверки `haystack` на пустоту.
|
||||
2. `haystack.front` – для получения первого элемента `haystack`.
|
||||
|
@ -1008,7 +1010,7 @@ unittest
|
|||
}
|
||||
```
|
||||
|
||||
(Обратите внимание на очередное удачное использование `reduce`.) Интересная деталь функции `average`: многоточие ... после параметра `values`, который является срезом. (Если бы это было не так или если бы параметр `values` не был последним в списке аргументов функции `average`, компилятор диагностировал бы это многоточие как ошибку.)
|
||||
(Обратите внимание на очередное удачное использование `reduce`.) Интересная деталь функции `average`: многоточие `...` после параметра `values`, который является срезом. (Если бы это было не так или если бы параметр `values` не был последним в списке аргументов функции `average`, компилятор диагностировал бы это многоточие как ошибку.)
|
||||
|
||||
Вызов функции `average` со срезом массива элементов типа `double` (как показано в последней строке теста модуля) ничем не примечателен. Однако благодаря многоточию эту функцию можно вызывать с любым числом аргументов, при условии что каждый из них можно привести к типу `double`. Компилятор автоматически сформирует из этих аргументов срез и передаст его в `average`.
|
||||
|
||||
|
|
|
@ -161,13 +161,11 @@ unittest
|
|||
|
||||
Вместо трех последних строк можно было бы использовать универсальную вспомогательную функцию `swap` из модуля `std.algorithm`: `swap(a1, a2)`, но явная запись процесса обмена нагляднее. На рис. 6.2 продемонстрированы привязки до и после обмена.
|
||||
|
||||
Сами объекты остаются на том же месте, то есть после создания они никогда не перемещаются в памяти. Просто замечательно, объект никогда не исчезнет: можно рассчитывать, что объект навсегда останется там, куда он был помещен при создании. (Сборщик мусора перерабатывает в фоновом режиме те объекты, которые больше не используются.) Ссылки на объекты (в данном случае `a1` и `a2`) можно заставить «смотреть в другую сторону», переназначив их привязку. Когда библиотека времени исполнения обнаруживает, что для какого-то объекта больше нет привязанных к нему ссылок, она может заново использовать выделенную под него память (этот процесс называется сбором мусора).[^1] Такое поведение
|
||||
|
||||

|
||||
|
||||
***Рис. 6.2.*** *Привязки до и после обмена. В процессе обмена меняются привязки к ссылкам; сами объекты остаются на том же месте*
|
||||
|
||||
в корне отличается от семантики *значения* (например, `int`), в случае которого нет никаких косвенных изменений или привязок: каждое имя прочно закреплено за значением, которым манипулируют с помощью этого идентификатора.
|
||||
Сами объекты остаются на том же месте, то есть после создания они никогда не перемещаются в памяти. Просто замечательно, объект никогда не исчезнет: можно рассчитывать, что объект навсегда останется там, куда он был помещен при создании. (Сборщик мусора перерабатывает в фоновом режиме те объекты, которые больше не используются.) Ссылки на объекты (в данном случае `a1` и `a2`) можно заставить «смотреть в другую сторону», переназначив их привязку. Когда библиотека времени исполнения обнаруживает, что для какого-то объекта больше нет привязанных к нему ссылок, она может заново использовать выделенную под него память (этот процесс называется сбором мусора).[^1] Такое поведение в корне отличается от семантики *значения* (например, `int`), в случае которого нет никаких косвенных изменений или привязок: каждое имя прочно закреплено за значением, которым манипулируют с помощью этого идентификатора.
|
||||
|
||||
Ссылка, не привязанная к какому-либо объекту, – это «пустая» ссылка (`null`). При инициализации по умолчанию с помощью свойства `.init` ссылки на классы получают значение `null`. Можно сравнивать ссылку с константой `null` и присваивать ссылке значение `null`. Следующие проверки пройдут успешно:
|
||||
|
||||
|
@ -401,10 +399,11 @@ this(uint h)
|
|||
|
||||
1. *Выделение памяти*. Библиотека времени исполнения выделяет участок «сырой» памяти в куче, достаточный для размещения нестатических полей объекта. Память подо все объекты, основанные на классах, выделяется динамически – в отличие от C++, в D нет способа выделить для объекта память в стеке[^2]. Если выделить память не удалось, построение объекта прерывается: порождается исключительная ситуация.
|
||||
|
||||
*Инициализация полей*. Каждое поле инициализируется своим значением по умолчанию. Как уже говорилось, в качестве значения поля по умолчанию выступает значение, указанное при объявлении поля в виде `= значение`, или при отсутствии такой записи значение свойства `.init` типа поля.
|
||||
2. *Инициализация полей*. Каждое поле инициализируется своим значением по умолчанию. Как уже говорилось, в качестве значения поля по умолчанию выступает значение, указанное при объявлении поля в виде `= значение`, или при отсутствии такой записи значение свойства `.init` типа поля.
|
||||
|
||||
2. *Брендирование*. После завершения инициализации полей значениями по умолчанию объекту присваивается статус полноправного экземпляра класса `T` (объект брендируется) еще *до* того, как будет вызван настоящий конструктор.
|
||||
3. *Вызов конструктора*. Наконец, компилятор инициирует вызов подходящего конструктора. Если класс не определяет собственный конструктор, этот шаг пропускается.
|
||||
3. *Брендирование*. После завершения инициализации полей значениями по умолчанию объекту присваивается статус полноправного экземпляра класса `T` (объект брендируется) еще *до* того, как будет вызван настоящий конструктор.
|
||||
|
||||
4. *Вызов конструктора*. Наконец, компилятор инициирует вызов подходящего конструктора. Если класс не определяет собственный конструктор, этот шаг пропускается.
|
||||
|
||||
Поскольку объект считается «живым» и правильно построенным сразу после инициализации по умолчанию, настоятельно рекомендуется использовать инициализирующие значения, которые всегда приводят объект в осмысленное состояние. Настоящий конструктор внесет затем свои поправки, приведя объект в другое интересное состояние (разумеется, также осмысленное).
|
||||
|
||||
|
@ -1375,7 +1374,9 @@ void main()
|
|||
void widgetize()
|
||||
{
|
||||
Widget w = new Widget;
|
||||
.../* Использование w */...
|
||||
...
|
||||
/* Использование w */
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1385,7 +1386,9 @@ void widgetize()
|
|||
void widgetize()
|
||||
{
|
||||
Widget w = new TextWidget;
|
||||
.../* Использование w */...
|
||||
...
|
||||
/* Использование w */
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1395,7 +1398,9 @@ void widgetize()
|
|||
void widgetize(string widgetClass)
|
||||
{
|
||||
Widget w = cast(Widget) Object.factory(widgetClass);
|
||||
... /* Использование w */...
|
||||
...
|
||||
/* Использование w */
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2649,7 +2654,7 @@ D полностью поддерживает технику невиртуал
|
|||
[^7]: Ф. Брукс «Мифический человеко-месяц». – Символ-Плюс, 2000.
|
||||
[^8]: `rhs` (от right hand side – справа от) – значение, в выражении расположенное справа от оператора. Аналогично `lhs` (от left hand side – слева от) – значение, в выражении расположенное слева от оператора. – *Прим. ред.*
|
||||
[^9]: Интересно, что семантика использования `opCmp` та же, что и в функциях сравнения памяти и строк в языке C. – *Прим. науч. ред.*
|
||||
[^10]: Виртуа льный метод – метод, который переопределяет другой метод или сам может быть переопределен. – *Прим. науч. ред.*
|
||||
[^10]: Виртуальный метод – метод, который переопределяет другой метод или сам может быть переопределен. – *Прим. науч. ред.*
|
||||
[^11]: Это напоминает виртуа льное наследование в С++. – *Прим. науч. ред.*
|
||||
[^12]: Сходный механизм используется при возвращении функцией делегата и образовании замыканий, однако следует учитывать, что компилятор выполняет описанные действия строго для предопределенных языком случаев (таких как внутренние классы и делегаты). Попытка функции вернуть указатель на локальную переменную ни к чему хорошему не приведет. – *Прим. науч. ред.*
|
||||
[^13]: Аргументы конструктора при создании анонимного класса передаются сразу после ключевого слова `class`, а если создается анонимный класс, реализующий список интерфейсов, то эти интерфейсы указываются через запятую после имени суперкласса. Пример: `new class(arg1, arg2) BaseClass, Interface1, Interface2 {};`. – *Прим. науч. ред.*
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
Применяя классы, основные типы и функции, можно написать много хороших программ. С параметризированными классами и функциями дело идет еще лучше. Но нередко мы с сожалением отмечаем, что по нескольким причинам классы не представляют собой инструмент с максимальной абстракцией типа.
|
||||
|
||||
Во-первых, классы подчиняются ссылочной семантике и из-за этого могут воплощать многие проектные решения не полностью или с ощутимыми накладными расходами. На практике трудно моделировать с помощью класса такую простую сущность, как точка с двумя или тремя координатами, если таких точек больше нескольких миллионов: разработчик оказывается перед непростым выбором – хорошая абстракция или приемлемое быстродействие. Кроме того, для линейной алгебры ссылочная семантика – большая морока. Попробуйте убедить математика или программиста-теоретика, что присваивание `a = b` должно делать из матрицы a лишь псевдоним матрицы `b`, а не отдельную копию! Даже такой простой тип, как массив, довольно накладно моделировать в виде класса в сравнении с мощной и лаконичной абстракцией массива, имеющейся в языке D (см. главу 4). Можно, конечно, сделать массивы «волшебными», но опыт то и дело показывает, что предоставлять множество «волшебных» типов, не воспроизводимых в пользовательском коде, – дурной тон и признак плохо спроектированного языка. Затраты на массив – всего два слова, а выделение памяти под экземпляр класса и использование дополнительного косвенного обращения означают большие накладные расходы по памяти и времени для всех примитивов массива. Даже такой простой тип, как `int`, нельзя выразить в виде класса дешево и элегантно (причем речь не об удобстве оператора). У такого класса, как `BigInt`, та же проблема: `a = b` делает нечто совершенно иное,
|
||||
Во-первых, классы подчиняются ссылочной семантике и из-за этого могут воплощать многие проектные решения не полностью или с ощутимыми накладными расходами. На практике трудно моделировать с помощью класса такую простую сущность, как точка с двумя или тремя координатами, если таких точек больше нескольких миллионов: разработчик оказывается перед непростым выбором – хорошая абстракция или приемлемое быстродействие. Кроме того, для линейной алгебры ссылочная семантика – большая морока. Попробуйте убедить математика или программиста-теоретика, что присваивание `a = b` должно делать из матрицы `a` лишь псевдоним матрицы `b`, а не отдельную копию! Даже такой простой тип, как массив, довольно накладно моделировать в виде класса в сравнении с мощной и лаконичной абстракцией массива, имеющейся в языке D (см. главу 4). Можно, конечно, сделать массивы «волшебными», но опыт то и дело показывает, что предоставлять множество «волшебных» типов, не воспроизводимых в пользовательском коде, – дурной тон и признак плохо спроектированного языка. Затраты на массив – всего два слова, а выделение памяти под экземпляр класса и использование дополнительного косвенного обращения означают большие накладные расходы по памяти и времени для всех примитивов массива. Даже такой простой тип, как `int`, нельзя выразить в виде класса дешево и элегантно (причем речь не об удобстве оператора). У такого класса, как `BigInt`, та же проблема: `a = b` делает нечто совершенно иное,
|
||||
чем соответствующая операция присваивания для типа `int`.
|
||||
|
||||
Во-вторых, классы живут вечно, а значит, с их помощью трудно моделировать ресурсы с выраженным *конечным* временем жизни (такие как дескрипторы файлов, дескрипторы графического контекста, мьютексы, сокеты и т. д.). Работая с такими ресурсами как с классами, нужно постоянно быть начеку, чтобы не забыть своевременно освободить инкапсулированные ресурсы с помощью метода, вроде `close` или `dispose`. В таких случаях обычно помогает инструкция `scope` (см. раздел 3.13), но лучше, когда подобная контекстная семантика инкапсулирована в типе – раз и навсегда.
|
||||
|
|
|
@ -53,17 +53,17 @@
|
|||
|
||||
*Таблица 11.1. Для различения файлов с исходным кодом на D используют ся метки порядка байтов. Шаблоны проверяются сверху вниз, первое же совпадение при сопоставлении устанавливает кодировку файла. `xx` – любое ненулевое значение байта*
|
||||
|
||||
|Если первые байты...|...то кодировка файла – ...|Игнорировать эти байты?|
|
||||
|-|-|:-:|
|
||||
|`00 00 FE FF`|UTF-32 с прямым порядком байтов[^1]|✓|
|
||||
|`FF FE 00 00`|UTF-32 с обратным порядком байтов[^2]|✓|
|
||||
|`FE FF`|UTF-16 с прямым порядком байтов|✓|
|
||||
|`FF FE`|UTF-16 с обратным порядком байтов|✓|
|
||||
|`00 00 00 xx`|UTF-32 с прямым порядком байтов||
|
||||
|`xx 00 00 00`|UTF-32 с обратным порядком байтов||
|
||||
|`00 xx`|UTF-16 с прямым порядком байтов||
|
||||
|`xx 00`|UTF-16 с обратным порядком байтов||
|
||||
|Что-то другое|UTF-8||
|
||||
| Если первые байты... | ...то кодировка файла – ... | Игнорировать эти байты? |
|
||||
| --- | --- | :-: |
|
||||
| `00 00 FE FF` | UTF-32 с прямым порядком байтов[^1] | ✓ |
|
||||
| `FF FE 00 00` | UTF-32 с обратным порядком байтов[^2] | ✓ |
|
||||
| `FE FF` | UTF-16 с прямым порядком байтов | ✓ |
|
||||
| `FF FE` | UTF-16 с обратным порядком байтов | ✓ |
|
||||
| `00 00 00 xx` | UTF-32 с прямым порядком байтов | |
|
||||
| `xx 00 00 00` | UTF-32 с обратным порядком байтов | |
|
||||
| `00 xx` | UTF-16 с прямым порядком байтов | |
|
||||
| `xx 00` | UTF-16 с обратным порядком байтов | |
|
||||
| Что-то другое | UTF-8 | |
|
||||
|
||||
В некоторых файлах метка порядка байтов отсутствует, но у D есть средство, позволяющее автоматически недвусмысленно определить кодировку. Процедура автоопределения тонко использует тот факт, что любой правильно построенный модуль на D должен начинаться хотя бы с нескольких знаков, встречающихся в кодировке ASCII, то есть с кодовых точек Юникода со значением меньше 128. Ведь в соответствии с грамматикой D правильно построенный модуль должен начинаться или с ключевого слова языка D (состоящего из знаков Юникода с ASCII-кодами), или с ASCII-пробела, или с комментария, который начинается с ASCII-знака `/`, или с пары директив, начинающихся с `#`, которые также должны состоять из ASCII-знаков. Если выполнить проверку на соответствие шаблонам из табл. 11.1, перебирая эти шаблоны сверху вниз, первое же совпадение недвусмысленно укажет кодировку. Если кодировка определена ошибочно, вреда от этого все равно не будет – файл, несомненно, и так ошибочен, поскольку начинается со знаков, которые не может содержать корректный код на D.
|
||||
|
||||
|
@ -642,8 +642,7 @@ module my_widget;
|
|||
|
||||
В этом месте определяются атрибуты `@safe`, `@trusted` и `@system`, которые позволяют модулю объявить о своем уровне безопасности. (Такой подход не нов; в языке Модула-3 применяется тот же подход, чтобы отличить небезопасные и безопасные модули.)
|
||||
|
||||
Код, размещенный после атрибута `@safe`, обязуется использовать ин
|
||||
струкции лишь из безопасного подмножества D, что означает:
|
||||
Код, размещенный после атрибута `@safe`, обязуется использовать инструкции лишь из безопасного подмножества D, что означает:
|
||||
|
||||
- никаких преобразований указателей в неуказатели (например, `int`), и наоборот;
|
||||
- никаких преобразований между указателями, типы которых не имеют отношения друг к другу;
|
||||
|
@ -959,32 +958,32 @@ void fun()
|
|||
|
||||
*Таблица 11.2. Обзор стандартных модулей*
|
||||
|
||||
|Модуль|Описание|
|
||||
|-|-|
|
||||
|`std.algorithm`|Этот модуль можно считать основой мощнейшей способности к обобщению, присущей языку. Вдохновлен стандартной библиотекой шаблонов C++ (Standard Template Library, STL). Содержит больше 70 важных алгоритмов, реализованных очень обобщенно. Большинство алгоритмов применяются к структурированным последовательностям идентичных элементов. В STL базовой абстракцией последовательности служит итератор, соответствующий примитив D – *диапазон*, для которого краткого обзора явно недостаточно; полное введение в диапазоны D доступно в Интернете|
|
||||
|`std.array`|Функции для удобства работы с массивами|
|
||||
|`std.bigint`|Целое число переменной длины с сильно оптимизированной реализацией|
|
||||
|`std.bitmanip`|Типы и часто используемые функции для низкоуровневых битовых операций|
|
||||
|`std.concurrency`|Средства параллельных вычислений (см. главу 13)|
|
||||
|`std.container`|Реализации разнообразных контейнеров|
|
||||
|`std.conv`|Универсальный магазин, удовлетворяющий любые нужды по преобразованиям. Здесь определены многие полезные функции, такие как `to` и `text`|
|
||||
|`std.datetime`|Полезные вещи, связанные с датой и временем|
|
||||
|`std.file`|Файловые утилиты. Зачастую этот модуль манип улирует файлами целиком; например, в нем есть функция `read`, которая считывает весь файл, при этом `std.file.read` и понятия не имеет о том, что можно открывать файл и читать его маленькими порциями (об этом заботится модуль `std.stdio`, см. далее)|
|
||||
|`std.functional`|Примитивы для определения и композиции функций|
|
||||
|`std.getopt`|Синтаксический анализ командной строки|
|
||||
|`std.json`|Обработка данных в формате JSON|
|
||||
|`std.math`|В высшей степени оптимизированные, часто используемые математические функции|
|
||||
|`std.numeric`|Общие числовые алгоритмы|
|
||||
|`std.path`|Утилиты для манипуляций с путями к файлам|
|
||||
|`std.random`|Разнообразные генераторы случайных чисел|
|
||||
|`std.range`|Определения и примитивы классификации, имеющие отношение к диапазонам|
|
||||
|`std.regex`|Обработчик регулярных выражений|
|
||||
|`std.stdio`|Стандартные библиотечные средства ввода/вывода, построенные на основе библиотеки `stdio` языка C. Входные и выходные файлы предоставляют интерфейсы в стиле диапазонов, благодаря чему многие алгоритмы, определенные в модуле `std.algorithm`, могут работать непосредственно с файлами|
|
||||
|`std.string`|Функции, специфичные для строк. Строки тесно связаны с `std.algorithm`, так что модуль `std.string`, относительно небольшой по размеру, в основном лишь ссылается (определяя псевдонимы) на части `std.algorithm`, применимые к строкам|
|
||||
|`std.traits`|Качества типов и интроспекция|
|
||||
|`std.typecons`|Средства для определения новых типов, таких как `Tuple`|
|
||||
|`std.utf`|Функции для манипулирования кодировками UTF|
|
||||
|`std.variant`|Объявление типа `Variant`, который является контейнером для хранения значения любого типа. `Variant` – это высокоуровневый `union`|
|
||||
| Модуль | Описание |
|
||||
| --- | --- |
|
||||
| `std.algorithm` | Этот модуль можно считать основой мощнейшей способности к обобщению, присущей языку. Вдохновлен стандартной библиотекой шаблонов C++ (Standard Template Library, STL). Содержит больше 70 важных алгоритмов, реализованных очень обобщенно. Большинство алгоритмов применяются к структурированным последовательностям идентичных элементов. В STL базовой абстракцией последовательности служит итератор, соответствующий примитив D – *диапазон*, для которого краткого обзора явно недостаточно; полное введение в диапазоны D доступно в Интернете |
|
||||
| `std.array` | Функции для удобства работы с массивами |
|
||||
| `std.bigint` | Целое число переменной длины с сильно оптимизированной реализацией |
|
||||
| `std.bitmanip` | Типы и часто используемые функции для низкоуровневых битовых операций |
|
||||
| `std.concurrency` | Средства параллельных вычислений (см. главу 13) |
|
||||
| `std.container` | Реализации разнообразных контейнеров |
|
||||
| `std.conv` | Универсальный магазин, удовлетворяющий любые нужды по преобразованиям. Здесь определены многие полезные функции, такие как `to` и `text` |
|
||||
| `std.datetime` | Полезные вещи, связанные с датой и временем |
|
||||
| `std.file` | Файловые утилиты. Зачастую этот модуль манип улирует файлами целиком; например, в нем есть функция `read`, которая считывает весь файл, при этом `std.file.read` и понятия не имеет о том, что можно открывать файл и читать его маленькими порциями (об этом заботится модуль `std.stdio`, см. далее) |
|
||||
| `std.functional` | Примитивы для определения и композиции функций |
|
||||
| `std.getopt` | Синтаксический анализ командной строки |
|
||||
| `std.json` | Обработка данных в формате JSON |
|
||||
| `std.math` | В высшей степени оптимизированные, часто используемые математические функции |
|
||||
| `std.numeric` | Общие числовые алгоритмы |
|
||||
| `std.path` | Утилиты для манипуляций с путями к файлам |
|
||||
| `std.random` | Разнообразные генераторы случайных чисел |
|
||||
| `std.range` | Определения и примитивы классификации, имеющие отношение к диапазонам |
|
||||
| `std.regex` | Обработчик регулярных выражений |
|
||||
| `std.stdio` | Стандартные библиотечные средства ввода/вывода, построенные на основе библиотеки `stdio` языка C. Входные и выходные файлы предоставляют интерфейсы в стиле диапазонов, благодаря чему многие алгоритмы, определенные в модуле `std.algorithm`, могут работать непосредственно с файлами |
|
||||
| `std.string` | Функции, специфичные для строк. Строки тесно связаны с `std.algorithm`, так что модуль `std.string`, относительно небольшой по размеру, в основном лишь ссылается (определяя псевдонимы) на части `std.algorithm`, применимые к строкам |
|
||||
| `std.traits` | Качества типов и интроспекция |
|
||||
| `std.typecons` | Средства для определения новых типов, таких как `Tuple` |
|
||||
| `std.utf` | Функции для манипулирования кодировками UTF |
|
||||
| `std.variant` | Объявление типа `Variant`, который является контейнером для хранения значения любого типа. `Variant` – это высокоуровневый `union` |
|
||||
|
||||
[В начало ⮍](#11-9-стандартная-библиотека-d) [Наверх ⮍](#11-расширение-масштаба)
|
||||
|
||||
|
@ -1391,7 +1390,7 @@ void fastProcess()
|
|||
[^2]: Обратный порядок байтов – от младшего к старшему байту. – *Прим. пер.*
|
||||
[^3]: «Shebang» – от англ. *sharp-bang* или *hash-bang*, произношение символов `#!` – *Прим. науч. ред.*
|
||||
[^4]: Текущие версии реализации позволяют включать модули на уровне классов и функций. – *Прим. науч. ред.*
|
||||
[^5]: В тексте / используется в качестве обобщенного разделителя; необходимо понимать, что реа льный разделитель зависит от системы.
|
||||
[^5]: В тексте / используется в качестве обобщенного разделителя; необходимо понимать, что реальный разделитель зависит от системы.
|
||||
[^6]: Описание этой части языка не было включено в оригинал книги, но поскольку данная возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^7]: Фобос (Phobos) – больший из двух спутников планеты Марс. «Марс» – изначальное название языка D (см. введение). Digital Mars (Цифровой Марс) – компания, разработавшая язык D и эталонную реализацию языка – компилятор `dmd` (от Digital Mars D). – *Прим. науч. ред.*
|
||||
[^8]: Описание этой части языка не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
|
|
Loading…
Reference in New Issue