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 как минимум неплохо смотрится на фоне других языков, разработчикам которых приходилось принимать решения того же плана.
|
||||
|
||||
|
@ -83,5 +75,5 @@ D – это язык, который последовательно стара
|
|||
|
||||
[🢀 <u>Содержание</u>](../../) **Введение** [<u>1. Знакомство с языком D</u> 🢂](../01-%D0%B7%D0%BD%D0%B0%D0%BA%D0%BE%D0%BC%D1%81%D1%82%D0%B2%D0%BE-%D1%81-%D1%8F%D0%B7%D1%8B%D0%BA%D0%BE%D0%BC-d/)
|
||||
|
||||
[^1]: Афоризм американского комика Граучо Маркса. – *Прим. ред.*
|
||||
[^2]: Название компилятора языка D `dmd` расшифровывается как Digital Mars D. Digital Mars – организация, которая занимается разработкой этого компилятора. – *Прим. пер.*
|
||||
[^1]: Афоризм американского комика Граучо Маркса. – *Прим. ред.*
|
||||
[^2]: Название компилятора языка D `dmd` расшифровывается как Digital Mars D. Digital Mars – организация, которая занимается разработкой этого компилятора. – *Прим. пер.*
|
||||
|
|
|
@ -932,12 +932,12 @@ void main()
|
|||
|
||||
[🢀 <u>Введение</u>](../00-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5/) **1. Знакомство с языком D** [<u>2. Основные типы данных. Выражения</u> 🢂](../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/)
|
||||
|
||||
[^1]: «Shebang» (от shell bang: shell – консоль, bang – восклицательный знак), или «shabang» (# – sharp) – обозначение пути к компилятору или интерпретатору в виде `#!/путь/к/программе`. – *Прим. пер.*
|
||||
[^2]: В этой книге под «параметром» понимается значение, используемое внутри функции, а под «аргументом» – значение, передаваемое в функцию извне.
|
||||
[^3]: `.idup` – свойство любого массива, возвращающее неизменяемую (immutable) копию массива. Про неизменяемость будет рассказано позже, пока же следует знать, что ключ ассоциативного массива должен быть неизменяемым. – *Прим. науч. ред.*
|
||||
[^4]: Если кто-то из ваших коллег прокачал самоуверенность до уровня Супермена, спросите его, что делает код `object.template fun<arg>()`, и вы увидите криптонит в действии.
|
||||
[^5]: Усугубляет ситуацию с угловыми скобками то, что `<<` и `>>` – тоже операторы.
|
||||
[^6]: Этот файл содержит текст пьесы «Гамлет». – *Прим. пер.*
|
||||
[^7]: Ham (англ.) – ветчина. – *Прим. пер.*
|
||||
[^8]: NaN (Not a Number, нечисло) – хорошее начальное значение по умолчанию для чисел с плавающей запятой. К сожалению, для целых чисел не существует эквивалентного начального значения.
|
||||
[^9]: Это не совсем так. Переменная-`аккумулятор` должна быть инициализирована значением `double.max` и соответственно переименована. – *Прим. науч. ред.*
|
||||
[^1]: «Shebang» (от shell bang: shell – консоль, bang – восклицательный знак), или «shabang» (# – sharp) – обозначение пути к компилятору или интерпретатору в виде `#!/путь/к/программе`. – *Прим. пер.*
|
||||
[^2]: В этой книге под «параметром» понимается значение, используемое внутри функции, а под «аргументом» – значение, передаваемое в функцию извне.
|
||||
[^3]: `.idup` – свойство любого массива, возвращающее неизменяемую (immutable) копию массива. Про неизменяемость будет рассказано позже, пока же следует знать, что ключ ассоциативного массива должен быть неизменяемым. – *Прим. науч. ред.*
|
||||
[^4]: Если кто-то из ваших коллег прокачал самоуверенность до уровня Супермена, спросите его, что делает код `object.template fun<arg>()`, и вы увидите криптонит в действии.
|
||||
[^5]: Усугубляет ситуацию с угловыми скобками то, что `<<` и `>>` – тоже операторы.
|
||||
[^6]: Этот файл содержит текст пьесы «Гамлет». – *Прим. пер.*
|
||||
[^7]: Ham (англ.) – ветчина. – *Прим. пер.*
|
||||
[^8]: NaN (Not a Number, нечисло) – хорошее начальное значение по умолчанию для чисел с плавающей запятой. К сожалению, для целых чисел не существует эквивалентного начального значения.
|
||||
[^9]: Это не совсем так. Переменная-`аккумулятор` должна быть инициализирована значением `double.max` и соответственно переименована. – *Прим. науч. ред.*
|
||||
|
|
|
@ -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,106 +1174,106 @@ 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-основные-типы-данных-выражения)
|
||||
|
||||
[🢀 <u>1. Знакомство с языком D</u>](../01-%D0%B7%D0%BD%D0%B0%D0%BA%D0%BE%D0%BC%D1%81%D1%82%D0%B2%D0%BE-%D1%81-%D1%8F%D0%B7%D1%8B%D0%BA%D0%BE%D0%BC-d/) **2. Основные типы данных. Выражения** [<u>3. Инструкции</u> 🢂](../03-%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D0%B8/)
|
||||
|
||||
[^1]: Впрочем, использование нелатинских букв является дурным тоном. – *Прим. науч. ред.*
|
||||
[^2]: С99 – обновленная спецификация C, в том числе добавляющая поддержку знаков Юникода. – *Прим. пер.*
|
||||
[^3]: Сам язык не поддерживает восьмеричные литералы, но поскольку они присутствуют в некоторых C-подобных языках, в стандартную библиотеку был добавлен соответствующий шаблон. Теперь запись `std.conv.octal!777` аналогична записи `0777` в C. – *Прим. науч. ред.*
|
||||
[^4]: Для тех, кто готов воспринимать теорию: автоматы на рис. 2.1 и 2.2 – это детерминированные конечные автоматы (ДКА).
|
||||
[^5]: В России в качестве разделителя целой и дробной части чисел с плавающей запятой принята запятая (поэтому и говорят: «числа с плавающей *запятой*»), однако в англоговорящих странах для этого служит точка, поэтому в языках программирования (обычно основанных на английском – международном языке информатики) разделителем является точка. – *Прим. пер.*
|
||||
[^6]: Показатель степени 10 по-английски – exponent, поэтому для его обозначения и используется буква `e`. – *Прим. пер.*
|
||||
[^7]: Запись `Ep` означает «умножить на 10 в степени `p`», то есть `p` – это порядок. – *Прим. пер.*
|
||||
[^8]: Степень по-английски – power, поэтому показатель степени 2 обозначается буквой `p`. – *Прим. пер.*
|
||||
[^9]: Да, синтаксис странноватый, но D скопировал его из стандарта C99, чтобы не изобретать свою нотацию с собственными выкрутасами, которых все равно не избежать.
|
||||
[^10]: Escape-последовательность (от англ. escape – избежать), экранирующая/управляющая последовательность – специальная комбинация знаков, отменяющая стандартную обработку компилятором следующих за ней знаков (они как бы «исключаются из рассмотрения»). – *Прим. пер.*
|
||||
[^11]: WYSIWIG – акроним «What You See Is What You Get» (что видишь, то и получишь) – способ представления, при котором данные в процессе редактирования выглядят так же, как и в результате обработки каким-либо инструментом (компилятором, после отображения браузером и т. п.). – *Прим. пер.*
|
||||
[^12]: Он же обратный апостроф. – *Прим. науч. ред.*
|
||||
[^13]: Префиксы `w` и `d` – от англ. wide (широкий) и double (двойной) – *Прим. науч. ред.*
|
||||
[^14]: В литерале массива допустима запятая, после которой нет элемента, например [1, 2,] – длина этого массива равна 2, а последняя запятая попросту игнорируется. Это сделано для удобства автоматических генераторов кода: при генерации текста литерала массива они конкатенируют строки вида `"очередной_элемент"`, не обрабатывая отдельно последний элемент, запятая после которого была бы не нужна. – *Прим. науч. ред.*
|
||||
[^15]: Заключенное в 1989 году соглашение между коммунистами и демократами, ознаменовавшее собой достижение компромисса между двумя партиями. В данном случае также ищется «компромиссный» тип. – *Прим. пер.*
|
||||
[^16]: In situ (лат.) – на месте. – *Прим. пер.*
|
||||
[^17]: От англ. left-value и right-value. – *Прим. науч. ред.*
|
||||
[^18]: Domain-specific embedded language (DSEL) – предметно-ориентированный встроенный язык. – *Прим. пер.*
|
||||
[^19]: Стандарт IEEE 754 определяет для чисел с плавающей запятой два разных двоичных представления для нуля: -0 и +0. Это порождает ряд неудобств, таких как исключение при сравнении чисел, рассмотренное здесь. С другой стороны, скорость многих вычислений увеличивается. Вы, скорее всего, будете редко использовать литерал `-0.0` в коде на D, но это значение может получиться неявно как результат вычислений, асимптотически приближающих отрицательные значения к нулю.
|
||||
[^1]: Впрочем, использование нелатинских букв является дурным тоном. – *Прим. науч. ред.*
|
||||
[^2]: С99 – обновленная спецификация C, в том числе добавляющая поддержку знаков Юникода. – *Прим. пер.*
|
||||
[^3]: Сам язык не поддерживает восьмеричные литералы, но поскольку они присутствуют в некоторых C-подобных языках, в стандартную библиотеку был добавлен соответствующий шаблон. Теперь запись `std.conv.octal!777` аналогична записи `0777` в C. – *Прим. науч. ред.*
|
||||
[^4]: Для тех, кто готов воспринимать теорию: автоматы на рис. 2.1 и 2.2 – это детерминированные конечные автоматы (ДКА).
|
||||
[^5]: В России в качестве разделителя целой и дробной части чисел с плавающей запятой принята запятая (поэтому и говорят: «числа с плавающей *запятой*»), однако в англоговорящих странах для этого служит точка, поэтому в языках программирования (обычно основанных на английском – международном языке информатики) разделителем является точка. – *Прим. пер.*
|
||||
[^6]: Показатель степени 10 по-английски – exponent, поэтому для его обозначения и используется буква `e`. – *Прим. пер.*
|
||||
[^7]: Запись `Ep` означает «умножить на 10 в степени `p`», то есть `p` – это порядок. – *Прим. пер.*
|
||||
[^8]: Степень по-английски – power, поэтому показатель степени 2 обозначается буквой `p`. – *Прим. пер.*
|
||||
[^9]: Да, синтаксис странноватый, но D скопировал его из стандарта C99, чтобы не изобретать свою нотацию с собственными выкрутасами, которых все равно не избежать.
|
||||
[^10]: Escape-последовательность (от англ. escape – избежать), экранирующая/управляющая последовательность – специальная комбинация знаков, отменяющая стандартную обработку компилятором следующих за ней знаков (они как бы «исключаются из рассмотрения»). – *Прим. пер.*
|
||||
[^11]: WYSIWIG – акроним «What You See Is What You Get» (что видишь, то и получишь) – способ представления, при котором данные в процессе редактирования выглядят так же, как и в результате обработки каким-либо инструментом (компилятором, после отображения браузером и т. п.). – *Прим. пер.*
|
||||
[^12]: Он же обратный апостроф. – *Прим. науч. ред.*
|
||||
[^13]: Префиксы `w` и `d` – от англ. wide (широкий) и double (двойной) – *Прим. науч. ред.*
|
||||
[^14]: В литерале массива допустима запятая, после которой нет элемента, например [1, 2,] – длина этого массива равна 2, а последняя запятая попросту игнорируется. Это сделано для удобства автоматических генераторов кода: при генерации текста литерала массива они конкатенируют строки вида `"очередной_элемент"`, не обрабатывая отдельно последний элемент, запятая после которого была бы не нужна. – *Прим. науч. ред.*
|
||||
[^15]: Заключенное в 1989 году соглашение между коммунистами и демократами, ознаменовавшее собой достижение компромисса между двумя партиями. В данном случае также ищется «компромиссный» тип. – *Прим. пер.*
|
||||
[^16]: In situ (лат.) – на месте. – *Прим. пер.*
|
||||
[^17]: От англ. left-value и right-value. – *Прим. науч. ред.*
|
||||
[^18]: Domain-specific embedded language (DSEL) – предметно-ориентированный встроенный язык. – *Прим. пер.*
|
||||
[^19]: Стандарт IEEE 754 определяет для чисел с плавающей запятой два разных двоичных представления для нуля: -0 и +0. Это порождает ряд неудобств, таких как исключение при сравнении чисел, рассмотренное здесь. С другой стороны, скорость многих вычислений увеличивается. Вы, скорее всего, будете редко использовать литерал `-0.0` в коде на D, но это значение может получиться неявно как результат вычислений, асимптотически приближающих отрицательные значения к нулю.
|
||||
|
|
|
@ -1097,48 +1097,48 @@ 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-инструкции)
|
||||
|
||||
[🢀 <u>2. Основные типы данных. Выражения</u>](../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/) **3. Инструкции** [<u>4. Массивы, ассоциативные массивы и строки</u> 🢂](../04-%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D1%8B-%D0%B0%D1%81%D1%81%D0%BE%D1%86%D0%B8%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B5-%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D1%8B-%D0%B8-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8/)
|
||||
|
||||
[^1]: Да-да, это «еще одно место, где используется ключевое слово `static»`.
|
||||
[^2]: Тип `enum` будет рассмотрен позже. Для понимания примера надо знать, что значения объявленные как `enum`, определены на этапе компиляции, неизменны и могут использоваться в конструкциях, вычисляемых на этапе компиляции. – *Прим. науч. ред.*
|
||||
[^3]: Существует также цикл `foreach_reverse`, который работает аналогично `foreach`, но перебирает значения в обратном порядке.
|
||||
[^4]: Идентификаторы, начинающиеся с двух подчеркиваний, описаны в разделе 2.1. – *Прим. пер.*
|
||||
[^5]: В стандартной библиотеке (STL) C++ для определения завершения цикла последовательно используется оператор `!=` на том основании, что (не)равенство – более общая форма сравнения, так как она применима к большему количеству типов. Подход D не менее общий, но при этом, когда это возможно, для повышения безопасности вычислений использует `<`, не проигрывая ни в обобщенности, ни в эффективности.
|
||||
[^6]: LIFO – акроним «Last In – First Out» (последним пришел – первым ушел). – *Прим. пер.*
|
||||
[^7]: CleanerUpper – «уборщик» (от англ. clean up – убирать, чистить). – *Прим. пер.*
|
||||
[^1]: Да-да, это «еще одно место, где используется ключевое слово `static»`.
|
||||
[^2]: Тип `enum` будет рассмотрен позже. Для понимания примера надо знать, что значения объявленные как `enum`, определены на этапе компиляции, неизменны и могут использоваться в конструкциях, вычисляемых на этапе компиляции. – *Прим. науч. ред.*
|
||||
[^3]: Существует также цикл `foreach_reverse`, который работает аналогично `foreach`, но перебирает значения в обратном порядке.
|
||||
[^4]: Идентификаторы, начинающиеся с двух подчеркиваний, описаны в разделе 2.1. – *Прим. пер.*
|
||||
[^5]: В стандартной библиотеке (STL) C++ для определения завершения цикла последовательно используется оператор `!=` на том основании, что (не)равенство – более общая форма сравнения, так как она применима к большему количеству типов. Подход D не менее общий, но при этом, когда это возможно, для повышения безопасности вычислений использует `<`, не проигрывая ни в обобщенности, ни в эффективности.
|
||||
[^6]: LIFO – акроним «Last In – First Out» (последним пришел – первым ушел). – *Прим. пер.*
|
||||
[^7]: CleanerUpper – «уборщик» (от англ. clean up – убирать, чистить). – *Прим. пер.*
|
||||
|
|
|
@ -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`.
|
||||
|
||||
Более того, получение среза массива `b` сокращает область памяти, «видимую» `b`, также без всякого копирования `b`. При условии что исходное состояние массива задано на рис. 4.2, выполнение инструкции
|
||||

|
||||
|
||||
***Рис. 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,76 +1288,76 @@ 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-массивы-ассоциативные-массивы-и-строки)
|
||||
|
||||
[🢀 <u>3. Инструкции</u>](../03-%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D0%B8/) **4. Массивы, ассоциативные массивы и строки** [<u>5. Данные и функции. Функциональный стиль</u> 🢂](../05-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%B8-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9-%D1%81%D1%82%D0%B8%D0%BB%D1%8C/)
|
||||
|
||||
[^1]: quadrupeds (англ.) – четвероногие. – *Прим. пер.*
|
||||
[^2]: Заметим также, что переход по нужному индексу статического многомерного массива происходит за один раз, а сам массив хранится в непрерывной области памяти. Например, для хранения массива `arr` типа `int[5][5]` выделяется область размером `5 * 5 * int.sizeof` байт, а переход по адресу `arr[2][2]` выглядит как `&arr + 2 * 5 + 2`. Если же статический массив размещается в сегменте данных (как глобальная переменная или как локальная с атрибутом `static`), а индексы известны на этапе компиляции, то переход по указателю вообще не потребуется. – *Прим. науч. ред.*
|
||||
[^3]: При этом для массива типа `V[K]` передаваемые ключи должны иметь тип `immutable(K)` или неявно приводимый к нему. Это требование введено для того, чтобы в процессе работы программы значение ключа не могло быть изменено косвенным образом, что повлекло бы нарушение структуры ассоциативного массива. – *Прим. науч. ред.*
|
||||
[^4]: Как уже говорилось, оператор `in` возвращает указатель на элемент, соответствующий ключу, или `null`, если такой ключ отсутствует в массиве. – *Прим. науч. ред.*
|
||||
[^5]: Кембрийский взрыв – неожиданное появление в раннекембрийских отложениях окаменелостей представителей многих подразделений животного царства на фоне отсутствия их окаменелостей или окаменелостей их предков в докембрийских отложениях. – *Прим. пер.*
|
||||
[^6]: В архитектуре x86 тип указатель размером в 4 байта соответствует двойному слову (`DW`), а слову соответствует тип `short` размером 2 байта. – *Прим. науч. ред.*
|
||||
[^1]: quadrupeds (англ.) – четвероногие. – *Прим. пер.*
|
||||
[^2]: Заметим также, что переход по нужному индексу статического многомерного массива происходит за один раз, а сам массив хранится в непрерывной области памяти. Например, для хранения массива `arr` типа `int[5][5]` выделяется область размером `5 * 5 * int.sizeof` байт, а переход по адресу `arr[2][2]` выглядит как `&arr + 2 * 5 + 2`. Если же статический массив размещается в сегменте данных (как глобальная переменная или как локальная с атрибутом `static`), а индексы известны на этапе компиляции, то переход по указателю вообще не потребуется. – *Прим. науч. ред.*
|
||||
[^3]: При этом для массива типа `V[K]` передаваемые ключи должны иметь тип `immutable(K)` или неявно приводимый к нему. Это требование введено для того, чтобы в процессе работы программы значение ключа не могло быть изменено косвенным образом, что повлекло бы нарушение структуры ассоциативного массива. – *Прим. науч. ред.*
|
||||
[^4]: Как уже говорилось, оператор `in` возвращает указатель на элемент, соответствующий ключу, или `null`, если такой ключ отсутствует в массиве. – *Прим. науч. ред.*
|
||||
[^5]: Кембрийский взрыв – неожиданное появление в раннекембрийских отложениях окаменелостей представителей многих подразделений животного царства на фоне отсутствия их окаменелостей или окаменелостей их предков в докембрийских отложениях. – *Прим. пер.*
|
||||
[^6]: В архитектуре x86 тип указатель размером в 4 байта соответствует двойному слову (`DW`), а слову соответствует тип `short` размером 2 байта. – *Прим. науч. ред.*
|
||||
|
|
|
@ -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`.
|
||||
|
||||
|
@ -1792,25 +1794,25 @@ struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m)
|
|||
|
||||
[🢀 <u>4. Массивы, ассоциативные массивы и строки</u>](../04-%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D1%8B-%D0%B0%D1%81%D1%81%D0%BE%D1%86%D0%B8%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B5-%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D1%8B-%D0%B8-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8/) **5. Данные и функции. Функциональный стиль** [<u>6. Классы. Объектно-ориентированный стиль</u> 🢂](../06-%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D1%8B-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9-%D1%81%D1%82%D0%B8%D0%BB%D1%8C/)
|
||||
|
||||
[^1]: Функция `find` ищет «иголку» (`needle`) в «стоге сена» (`haystack`). – *Прим. науч. ред.*
|
||||
[^2]: Следует подчеркнуть, что проверка выполнения подобных соглашений выполняется на этапе компиляции, и если компилятор обмануть, например с помощью приведения типов, то соглашения можно нарушить. Пример: `(cast(int[])data)[5] = 42;` даст именно то, что ожидается. Но это уже моветон. – *Прим. науч. ред.*
|
||||
[^3]: На самом деле, `in` означает `scope const`, однако семантика `scope` не до конца продумана и, возможно, в дальнейшем `scope` вообще исчезнет из языка. – *Прим. науч. ред.*
|
||||
[^4]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность есть в текущих реализациях языка, мы добавили ее описание. – *Прим. науч. ред.*
|
||||
[^5]: На самом деле, их *можно* инициализировать только константами, а можно вообще не инициализировать (тогда они принимают значение по умолчанию). – *Прим. науч. ред.*
|
||||
[^6]: Именно этот момент делает «частичный порядок» «частичным». В случае отношения полного порядка (например ≤ для действительных чисел) неупорядоченных элементов нет.
|
||||
[^7]: Речь о ежедневном комиксе американского художника Билла Уоттерсона «Кельвин и Хоббс». – *Прим. пер.*
|
||||
[^8]: Тот же подход используют ML и другие реализации функциональных языков.
|
||||
[^9]: Премия Дарвина – виртуальная премия, ежегодно присуждаемая тем, кто наиболее глупым способом лишился жизни или способности к зачатию, в результате не внеся свой вклад в генофонд человечества (и тем самым улучшив его). – *Прим. пер.*
|
||||
[^10]: Хотя в приведенном примере о типе аргумента `a` ничего не сказано, текущая на момент выпуска книги версия компилятора 2.057 работает указанным образом только в том случае, если `a` – массив. В ответ на пример `(7).someprop()` для функции `void someprop(int a){}` компилятор скажет, что нет свойства `someprop` для типа `int`. – *Прим. науч. ред.*
|
||||
[^11]: Версия компилятора 2.057 не поддерживает атрибуты, объявляемые пользователем. В будущем такая поддержка может появиться. – *Прим. науч. ред.*
|
||||
[^12]: На момент выхода книги такое поведение по умолчанию носило рекомендательный характер. Функция без аргументов и без атрибута `@property` могла вызываться как с пустой парой скобок, так и без. Так сделано из соображений обратной совместимости с кодом, написанным до ввода данного атрибута. Заставить компилятор проверять корректность использования скобок позволяет ключ компиляции `-property` (`dmd` 2.057). В дальнейшем некорректное применение скобок может быть запрещено, поэтому там, где требуется функция, ведущая себя как свойство, следует использовать `@property`. – *Прим. науч. ред.*
|
||||
[^13]: Инлайнинг (inline-подстановка) – подстановка кода функции в месте ее вызова. Позволяет снизить накладные расходы на вызов функции при передаче аргументов, переходе по адресу, обратном переходе, а также нагрузку на кэш памяти процессора. В версиях языка C до C99 это достигалось с помощью макросов, в C99 и С++ появились ключевое слово `inline` и inline-подстановка методов классов, описанных внутри описания класса. В языке D inline-подстановка отдается на откуп компилятору. Компилятор будет сам решать, где рационально ее применить, а где – нет. – *Прим. науч. ред.*
|
||||
[^14]: Reduce (англ.) – сокращать, сводить. – *Прим. науч. ред.*
|
||||
[^15]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание. – *Прим. науч. ред.*
|
||||
[^16]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^17]: В данном контексте речь идет об изменениях, которые повлияли бы на последующие вызовы функции, например об изменении глобальных переменных. – *Прим. науч. ред.*
|
||||
[^18]: «O» большое – математическое обозначение, применяемое при оценке асимптотической сложности алгоритма. – *Прим. ред.*
|
||||
[^19]: Равенство *c* нулю также допустимо, но соответствующая теоретическая часть гораздо сложнее, потому ограничимся значениями *c* > 0.
|
||||
[^20]: Непонятно как, но алгоритм Евклида всегда умудряется попадать в хорошие (хм...) книги по программированию.
|
||||
[^21]: Распространенный в США и Канаде мем, изначально связанный с фаст-фудом. – *Прим. ред.*
|
||||
[^22]: Многие из этих ограничений уже сняты. – *Прим. науч. ред.*
|
||||
[^1]: Функция `find` ищет «иголку» (`needle`) в «стоге сена» (`haystack`). – *Прим. науч. ред.*
|
||||
[^2]: Следует подчеркнуть, что проверка выполнения подобных соглашений выполняется на этапе компиляции, и если компилятор обмануть, например с помощью приведения типов, то соглашения можно нарушить. Пример: `(cast(int[])data)[5] = 42;` даст именно то, что ожидается. Но это уже моветон. – *Прим. науч. ред.*
|
||||
[^3]: На самом деле, `in` означает `scope const`, однако семантика `scope` не до конца продумана и, возможно, в дальнейшем `scope` вообще исчезнет из языка. – *Прим. науч. ред.*
|
||||
[^4]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность есть в текущих реализациях языка, мы добавили ее описание. – *Прим. науч. ред.*
|
||||
[^5]: На самом деле, их *можно* инициализировать только константами, а можно вообще не инициализировать (тогда они принимают значение по умолчанию). – *Прим. науч. ред.*
|
||||
[^6]: Именно этот момент делает «частичный порядок» «частичным». В случае отношения полного порядка (например ≤ для действительных чисел) неупорядоченных элементов нет.
|
||||
[^7]: Речь о ежедневном комиксе американского художника Билла Уоттерсона «Кельвин и Хоббс». – *Прим. пер.*
|
||||
[^8]: Тот же подход используют ML и другие реализации функциональных языков.
|
||||
[^9]: Премия Дарвина – виртуальная премия, ежегодно присуждаемая тем, кто наиболее глупым способом лишился жизни или способности к зачатию, в результате не внеся свой вклад в генофонд человечества (и тем самым улучшив его). – *Прим. пер.*
|
||||
[^10]: Хотя в приведенном примере о типе аргумента `a` ничего не сказано, текущая на момент выпуска книги версия компилятора 2.057 работает указанным образом только в том случае, если `a` – массив. В ответ на пример `(7).someprop()` для функции `void someprop(int a){}` компилятор скажет, что нет свойства `someprop` для типа `int`. – *Прим. науч. ред.*
|
||||
[^11]: Версия компилятора 2.057 не поддерживает атрибуты, объявляемые пользователем. В будущем такая поддержка может появиться. – *Прим. науч. ред.*
|
||||
[^12]: На момент выхода книги такое поведение по умолчанию носило рекомендательный характер. Функция без аргументов и без атрибута `@property` могла вызываться как с пустой парой скобок, так и без. Так сделано из соображений обратной совместимости с кодом, написанным до ввода данного атрибута. Заставить компилятор проверять корректность использования скобок позволяет ключ компиляции `-property` (`dmd` 2.057). В дальнейшем некорректное применение скобок может быть запрещено, поэтому там, где требуется функция, ведущая себя как свойство, следует использовать `@property`. – *Прим. науч. ред.*
|
||||
[^13]: Инлайнинг (inline-подстановка) – подстановка кода функции в месте ее вызова. Позволяет снизить накладные расходы на вызов функции при передаче аргументов, переходе по адресу, обратном переходе, а также нагрузку на кэш памяти процессора. В версиях языка C до C99 это достигалось с помощью макросов, в C99 и С++ появились ключевое слово `inline` и inline-подстановка методов классов, описанных внутри описания класса. В языке D inline-подстановка отдается на откуп компилятору. Компилятор будет сам решать, где рационально ее применить, а где – нет. – *Прим. науч. ред.*
|
||||
[^14]: Reduce (англ.) – сокращать, сводить. – *Прим. науч. ред.*
|
||||
[^15]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание. – *Прим. науч. ред.*
|
||||
[^16]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^17]: В данном контексте речь идет об изменениях, которые повлияли бы на последующие вызовы функции, например об изменении глобальных переменных. – *Прим. науч. ред.*
|
||||
[^18]: «O» большое – математическое обозначение, применяемое при оценке асимптотической сложности алгоритма. – *Прим. ред.*
|
||||
[^19]: Равенство *c* нулю также допустимо, но соответствующая теоретическая часть гораздо сложнее, потому ограничимся значениями *c* > 0.
|
||||
[^20]: Непонятно как, но алгоритм Евклида всегда умудряется попадать в хорошие (хм...) книги по программированию.
|
||||
[^21]: Распространенный в США и Канаде мем, изначально связанный с фаст-фудом. – *Прим. ред.*
|
||||
[^22]: Многие из этих ограничений уже сняты. – *Прим. науч. ред.*
|
||||
|
|
|
@ -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 */
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2640,20 +2645,20 @@ D полностью поддерживает технику невиртуал
|
|||
|
||||
[🢀 <u>5. Данные и функции. Функциональный стиль</u>](../05-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%B8-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9-%D1%81%D1%82%D0%B8%D0%BB%D1%8C/) **6. Классы. Объектно-ориентированный стиль** [<u>7. Другие пользовательские типы</u> 🢂](../07-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B/)
|
||||
|
||||
[^1]: Язык D также предоставляет возможность «ручного» управления памятью (manual memory management) и на данный момент позволяет принудительно уничтожать объекты с помощью оператора delete: `delete obj;`, при этом значение ссылки `obj` будет установлено в `null` (см. ниже), а память, выделенная под объект, будет освобождена. Если `obj` уже содержит `null`, ничего не произойдет. Однако следует соблюдать осторожность: повторное уничтожение одного объекта или обращение к удаленному объекту по другой ссылке приведет к катастрофическим последствиям (сбои и порча данных в памяти, источники которых порой очень трудно обнаружить), и эта опасность усугубляет необходимость в сборщике мусора. Из-за этих рисков оператор `delete` планируют убрать из самого языка, оставив в виде функции в стандартной библиотеке. Но при этом ручное управление памятью позволяет более эффективно ее использовать. Вердикт: задействуйте эту возможность, если уверены, что на момент вызова `delete` объект `obj` точно не удален и `obj` – последняя ссылка на данный объект, и не удивляйтесь, если в один прекрасный день `delete` исчезнет из реализаций языка. – *Прим. науч. ред.*
|
||||
[^2]: На данный момент реализации D предоставляют средства выделения памяти под классы в стеке (с помощью класса памяти `scope`) или вообще в любом фрагменте памяти (с помощью классовых аллокаторов и деаллокаторов). Но поскольку эти возможности небезопасны, они могут быть удалены из языка, так что не рассчитывайте на их вечное существование. – *Прим. науч. ред.*
|
||||
[^3]: В текущих реализациях использование `void` не влияет на производительность, так как все поля класса инициализируются «одним махом» копированием памяти из `.init` для экземпляров класса. – *Прим. науч. ред.*
|
||||
[^4]: В соответствии с предыдущим примечанием сегодня этот тест не пройдет. – *Прим. науч. ред.*
|
||||
[^5]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность имеется в языке, мы включили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^6]: Образ из книги «Краткая история времени» Стивена Хокинга: Вселенная как плоский мир, стоящий на спине гигантской черепахи, «та – на другой черепахе, та – тоже на черепахе, и так все ниже и ниже». – *Прим. ред.*
|
||||
[^7]: Ф. Брукс «Мифический человеко-месяц». – Символ-Плюс, 2000.
|
||||
[^8]: `rhs` (от right hand side – справа от) – значение, в выражении расположенное справа от оператора. Аналогично `lhs` (от left hand side – слева от) – значение, в выражении расположенное слева от оператора. – *Прим. ред.*
|
||||
[^9]: Интересно, что семантика использования `opCmp` та же, что и в функциях сравнения памяти и строк в языке C. – *Прим. науч. ред.*
|
||||
[^10]: Виртуа льный метод – метод, который переопределяет другой метод или сам может быть переопределен. – *Прим. науч. ред.*
|
||||
[^11]: Это напоминает виртуа льное наследование в С++. – *Прим. науч. ред.*
|
||||
[^12]: Сходный механизм используется при возвращении функцией делегата и образовании замыканий, однако следует учитывать, что компилятор выполняет описанные действия строго для предопределенных языком случаев (таких как внутренние классы и делегаты). Попытка функции вернуть указатель на локальную переменную ни к чему хорошему не приведет. – *Прим. науч. ред.*
|
||||
[^13]: Аргументы конструктора при создании анонимного класса передаются сразу после ключевого слова `class`, а если создается анонимный класс, реализующий список интерфейсов, то эти интерфейсы указываются через запятую после имени суперкласса. Пример: `new class(arg1, arg2) BaseClass, Interface1, Interface2 {};`. – *Прим. науч. ред.*
|
||||
[^14]: К сожалению, текущая на момент выхода книги версия компилятора допускала только одно объявление `alias this`. – *Прим. науч. ред.*
|
||||
[^15]: Deus ex machina («бог из машины») – в древнегреческом театре: бог, спускающийся с небес (изображающий его актер мог «летать» при помощи механического крана) и решающий все проблемы героев. В переносном смысле – неожиданная удачная развязка неразрешимой ситуации. – *Прим. ред.*
|
||||
[^16]: Описание этой части языка намеренно не было приведено в оригинале книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^17]: Описание этой части языка намеренно не было приведено в оригинале книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^1]: Язык D также предоставляет возможность «ручного» управления памятью (manual memory management) и на данный момент позволяет принудительно уничтожать объекты с помощью оператора delete: `delete obj;`, при этом значение ссылки `obj` будет установлено в `null` (см. ниже), а память, выделенная под объект, будет освобождена. Если `obj` уже содержит `null`, ничего не произойдет. Однако следует соблюдать осторожность: повторное уничтожение одного объекта или обращение к удаленному объекту по другой ссылке приведет к катастрофическим последствиям (сбои и порча данных в памяти, источники которых порой очень трудно обнаружить), и эта опасность усугубляет необходимость в сборщике мусора. Из-за этих рисков оператор `delete` планируют убрать из самого языка, оставив в виде функции в стандартной библиотеке. Но при этом ручное управление памятью позволяет более эффективно ее использовать. Вердикт: задействуйте эту возможность, если уверены, что на момент вызова `delete` объект `obj` точно не удален и `obj` – последняя ссылка на данный объект, и не удивляйтесь, если в один прекрасный день `delete` исчезнет из реализаций языка. – *Прим. науч. ред.*
|
||||
[^2]: На данный момент реализации D предоставляют средства выделения памяти под классы в стеке (с помощью класса памяти `scope`) или вообще в любом фрагменте памяти (с помощью классовых аллокаторов и деаллокаторов). Но поскольку эти возможности небезопасны, они могут быть удалены из языка, так что не рассчитывайте на их вечное существование. – *Прим. науч. ред.*
|
||||
[^3]: В текущих реализациях использование `void` не влияет на производительность, так как все поля класса инициализируются «одним махом» копированием памяти из `.init` для экземпляров класса. – *Прим. науч. ред.*
|
||||
[^4]: В соответствии с предыдущим примечанием сегодня этот тест не пройдет. – *Прим. науч. ред.*
|
||||
[^5]: Описание этой части языка намеренно не было включено в оригинал книги, но поскольку эта возможность имеется в языке, мы включили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^6]: Образ из книги «Краткая история времени» Стивена Хокинга: Вселенная как плоский мир, стоящий на спине гигантской черепахи, «та – на другой черепахе, та – тоже на черепахе, и так все ниже и ниже». – *Прим. ред.*
|
||||
[^7]: Ф. Брукс «Мифический человеко-месяц». – Символ-Плюс, 2000.
|
||||
[^8]: `rhs` (от right hand side – справа от) – значение, в выражении расположенное справа от оператора. Аналогично `lhs` (от left hand side – слева от) – значение, в выражении расположенное слева от оператора. – *Прим. ред.*
|
||||
[^9]: Интересно, что семантика использования `opCmp` та же, что и в функциях сравнения памяти и строк в языке C. – *Прим. науч. ред.*
|
||||
[^10]: Виртуальный метод – метод, который переопределяет другой метод или сам может быть переопределен. – *Прим. науч. ред.*
|
||||
[^11]: Это напоминает виртуа льное наследование в С++. – *Прим. науч. ред.*
|
||||
[^12]: Сходный механизм используется при возвращении функцией делегата и образовании замыканий, однако следует учитывать, что компилятор выполняет описанные действия строго для предопределенных языком случаев (таких как внутренние классы и делегаты). Попытка функции вернуть указатель на локальную переменную ни к чему хорошему не приведет. – *Прим. науч. ред.*
|
||||
[^13]: Аргументы конструктора при создании анонимного класса передаются сразу после ключевого слова `class`, а если создается анонимный класс, реализующий список интерфейсов, то эти интерфейсы указываются через запятую после имени суперкласса. Пример: `new class(arg1, arg2) BaseClass, Interface1, Interface2 {};`. – *Прим. науч. ред.*
|
||||
[^14]: К сожалению, текущая на момент выхода книги версия компилятора допускала только одно объявление `alias this`. – *Прим. науч. ред.*
|
||||
[^15]: Deus ex machina («бог из машины») – в древнегреческом театре: бог, спускающийся с небес (изображающий его актер мог «летать» при помощи механического крана) и решающий все проблемы героев. В переносном смысле – неожиданная удачная развязка неразрешимой ситуации. – *Прим. ред.*
|
||||
[^16]: Описание этой части языка намеренно не было приведено в оригинале книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^17]: Описание этой части языка намеренно не было приведено в оригинале книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
|
|
|
@ -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), но лучше, когда подобная контекстная семантика инкапсулирована в типе – раз и навсегда.
|
||||
|
@ -1993,7 +1993,7 @@ void main()
|
|||
|
||||
[🢀 <u>6. Классы. Объектно-ориентированный стиль</u>](../06-%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D1%8B-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9-%D1%81%D1%82%D0%B8%D0%BB%D1%8C/) **7. Другие пользовательские типы** [<u>8. Квалификаторы типа</u> 🢂](../08-%D0%BA%D0%B2%D0%B0%D0%BB%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D1%80%D1%8B-%D1%82%D0%B8%D0%BF%D0%B0/)
|
||||
|
||||
[^1]: Не считая эквивалентных имен, создаваемых с помощью `alias`, о чем мы еще поговорим в этой главе (см. раздел 7.4).
|
||||
[^2]: Термин «клуктура» предложил Бартош Милевски.
|
||||
[^3]: Кроме того, `‹код1›` может сохранить указатель на значение `w`, которое использует `‹код2›`.
|
||||
[^4]: На момент написания оригинала книги данная возможность отсутствовала, но поскольку теперь она существует, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^1]: Не считая эквивалентных имен, создаваемых с помощью `alias`, о чем мы еще поговорим в этой главе (см. раздел 7.4).
|
||||
[^2]: Термин «клуктура» предложил Бартош Милевски.
|
||||
[^3]: Кроме того, `‹код1›` может сохранить указатель на значение `w`, которое использует `‹код2›`.
|
||||
[^4]: На момент написания оригинала книги данная возможность отсутствовала, но поскольку теперь она существует, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
|
|
|
@ -561,7 +561,7 @@ class Y
|
|||
|
||||
[🢀 7. Другие пользовательские типы](../07-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B/) 8. Квалификаторы типа [9. Обработка ошибок 🢂](../09-%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D0%BE%D1%88%D0%B8%D0%B1%D0%BE%D0%BA/)
|
||||
|
||||
[^1]: Такой подход был избран для квалификатора `const` в C++.
|
||||
[^2]: Это решение было предложено Саймоном Пейтоном-Джонсом.
|
||||
[^3]: Кроме того, у любого массива `T[]`, `const(T)[]` и `immutable(T)[]` есть свойство `dup`, возвращающее копию массива типа `T[]`, и свойство `idup`, возвращающее копию типа `immutable(T)[]`. – *Прим. науч. ред.*
|
||||
[^4]: Приведенную ниже функцию можно было бы объявить как `void print(in int[] data);`, что означает в точности то же самое, но несколько лучше смотрится. – *Прим. науч. ред.*
|
||||
[^1]: Такой подход был избран для квалификатора `const` в C++.
|
||||
[^2]: Это решение было предложено Саймоном Пейтоном-Джонсом.
|
||||
[^3]: Кроме того, у любого массива `T[]`, `const(T)[]` и `immutable(T)[]` есть свойство `dup`, возвращающее копию массива типа `T[]`, и свойство `idup`, возвращающее копию типа `immutable(T)[]`. – *Прим. науч. ред.*
|
||||
[^4]: Приведенную ниже функцию можно было бы объявить как `void print(in int[] data);`, что означает в точности то же самое, но несколько лучше смотрится. – *Прим. науч. ред.*
|
||||
|
|
|
@ -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-расширение-масштаба)
|
||||
|
||||
|
@ -1387,14 +1386,14 @@ void fastProcess()
|
|||
|
||||
[🢀 <u>10. Контрактное программирование</u>](../10-%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5/) **11. Расширение масштаба** [<u>12. Перегрузка операторов</u> 🢂](../12-%D0%BF%D0%B5%D1%80%D0%B5%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%B2/)
|
||||
|
||||
[^1]: Прямой порядок байтов – от старшего к младшему байту. – *Прим. пер.*
|
||||
[^2]: Обратный порядок байтов – от младшего к старшему байту. – *Прим. пер.*
|
||||
[^3]: «Shebang» – от англ. *sharp-bang* или *hash-bang*, произношение символов `#!` – *Прим. науч. ред.*
|
||||
[^4]: Текущие версии реализации позволяют включать модули на уровне классов и функций. – *Прим. науч. ред.*
|
||||
[^5]: В тексте / используется в качестве обобщенного разделителя; необходимо понимать, что реа льный разделитель зависит от системы.
|
||||
[^6]: Описание этой части языка не было включено в оригинал книги, но поскольку данная возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^7]: Фобос (Phobos) – больший из двух спутников планеты Марс. «Марс» – изначальное название языка D (см. введение). Digital Mars (Цифровой Марс) – компания, разработавшая язык D и эталонную реализацию языка – компилятор `dmd` (от Digital Mars D). – *Прим. науч. ред.*
|
||||
[^8]: Описание этой части языка не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^9]: Например, есть хороший учебник для вузов «Assembler» В. И. Юрова. – *Прим. науч. ред.*
|
||||
[^10]: Ассемблер dmd2.052 не поддерживает доступ к регистру `RIP`. Возможно, данная функция появится позже. Ну а пока вместо `mov AL, [RIP];` вы можете написать мантру `db 0x8A, 0x05; di 0x00000000;`, тем самым сообщив свое желание на языке процессора. Помните: если транслятор не понимает некоторые символы или инструкции, вы можете транслировать ассемблерный код в машинный сторонним транслятором и вставить в свой ассемблерный код числовое представление команды, воспользовавшись псевдоинструкциями семейства `db`. – *Прим. науч. ред.*
|
||||
[^11]: Компилятор dmd2.057 пока трудно назвать промышленным компилятором, поэтому упомянутого механизма в нем пока нет, а вот компилятор языка C `gcc` предоставляет возможность указать целевую платформу. Это позволяет получить максимально эффективный машинный код для данной платформы, при этом в код на языке C вносить изменения не нужно. Читателям, нуждающимся в компиляторах D, способных генерировать более оптимизированный код, следует обратить внимание на проекты GDC (GNU D compiler) и LDC (LLVM D compiler) компиляторов D, построенных на базе генераторов кода GCC и LLVM. – *Прим. науч. ред.*
|
||||
[^1]: Прямой порядок байтов – от старшего к младшему байту. – *Прим. пер.*
|
||||
[^2]: Обратный порядок байтов – от младшего к старшему байту. – *Прим. пер.*
|
||||
[^3]: «Shebang» – от англ. *sharp-bang* или *hash-bang*, произношение символов `#!` – *Прим. науч. ред.*
|
||||
[^4]: Текущие версии реализации позволяют включать модули на уровне классов и функций. – *Прим. науч. ред.*
|
||||
[^5]: В тексте / используется в качестве обобщенного разделителя; необходимо понимать, что реальный разделитель зависит от системы.
|
||||
[^6]: Описание этой части языка не было включено в оригинал книги, но поскольку данная возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^7]: Фобос (Phobos) – больший из двух спутников планеты Марс. «Марс» – изначальное название языка D (см. введение). Digital Mars (Цифровой Марс) – компания, разработавшая язык D и эталонную реализацию языка – компилятор `dmd` (от Digital Mars D). – *Прим. науч. ред.*
|
||||
[^8]: Описание этой части языка не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^9]: Например, есть хороший учебник для вузов «Assembler» В. И. Юрова. – *Прим. науч. ред.*
|
||||
[^10]: Ассемблер dmd2.052 не поддерживает доступ к регистру `RIP`. Возможно, данная функция появится позже. Ну а пока вместо `mov AL, [RIP];` вы можете написать мантру `db 0x8A, 0x05; di 0x00000000;`, тем самым сообщив свое желание на языке процессора. Помните: если транслятор не понимает некоторые символы или инструкции, вы можете транслировать ассемблерный код в машинный сторонним транслятором и вставить в свой ассемблерный код числовое представление команды, воспользовавшись псевдоинструкциями семейства `db`. – *Прим. науч. ред.*
|
||||
[^11]: Компилятор dmd2.057 пока трудно назвать промышленным компилятором, поэтому упомянутого механизма в нем пока нет, а вот компилятор языка C `gcc` предоставляет возможность указать целевую платформу. Это позволяет получить максимально эффективный машинный код для данной платформы, при этом в код на языке C вносить изменения не нужно. Читателям, нуждающимся в компиляторах D, способных генерировать более оптимизированный код, следует обратить внимание на проекты GDC (GNU D compiler) и LDC (LLVM D compiler) компиляторов D, построенных на базе генераторов кода GCC и LLVM. – *Прим. науч. ред.*
|
||||
|
|
|
@ -1013,7 +1013,7 @@ unittest
|
|||
|
||||
[🢀 <u>11. Расширение масштаба</u>](../11-%D1%80%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B0%D1%81%D1%88%D1%82%D0%B0%D0%B1%D0%B0/) **12. Перегрузка операторов** [<u>13. Параллельные вычисления</u> 🢂](../13-%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F/)
|
||||
|
||||
[^1]: Автор использует понятия «тип» и «алгебра» не совсем точно. Тип определяет множество значений и множество операций, производимых над ними. Алгебра – это набор операций над определенным множеством. То есть уточнение «с алгебрами» – избыточно. – *Прим. науч. ред.*
|
||||
[^2]: В данном коде отсутствует проверка перехода за границы для оператора отрицания. – *Прим. науч. ред.*
|
||||
[^3]: Для перегрузки `foreach_reverse` служат примитивы `popBack` и `back` аналогичного назначения. – *Прим. науч. ред.*
|
||||
[^4]: Существует также оператор `opApplyReverse`, предназначенный для перегрузки `foreach_reverse` и действующий аналогично `opApply` для `foreach`. – *Прим. науч. ред.*
|
||||
[^1]: Автор использует понятия «тип» и «алгебра» не совсем точно. Тип определяет множество значений и множество операций, производимых над ними. Алгебра – это набор операций над определенным множеством. То есть уточнение «с алгебрами» – избыточно. – *Прим. науч. ред.*
|
||||
[^2]: В данном коде отсутствует проверка перехода за границы для оператора отрицания. – *Прим. науч. ред.*
|
||||
[^3]: Для перегрузки `foreach_reverse` служат примитивы `popBack` и `back` аналогичного назначения. – *Прим. науч. ред.*
|
||||
[^4]: Существует также оператор `opApplyReverse`, предназначенный для перегрузки `foreach_reverse` и действующий аналогично `opApply` для `foreach`. – *Прим. науч. ред.*
|
||||
|
|
|
@ -1305,16 +1305,16 @@ D предлагает широкий спектр средств для раб
|
|||
|
||||
[🢀 <u>12. Перегрузка операторов</u>](../12-%D0%BF%D0%B5%D1%80%D0%B5%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%B2/) **13. Параллельные вычисления** [<u>Содержание</u> 🢂](../../)
|
||||
|
||||
[^1]: Число транзисторов на кристалл будет увеличиваться вдвое каждые 24 месяца. – *Прим. пер.*
|
||||
[^2]: Далее речь идет о параллельных вычислениях в целом и не рассматриваются распараллеливание операций над векторами и другие специализированные параллельные функции ядра.
|
||||
[^3]: Что иронично, поскольку во времена классической многопоточности разделение памяти было быстрее, а обмен сообщениями – медленнее.
|
||||
[^4]: Даже заголовок раздела был изменен с «Потоки» на «Параллельные вычисления», чтобы подчеркнуть, что потоки – это не что иное, как одна из моделей параллельных вычислений.
|
||||
[^5]: Процессы языка Erlang отличаются от процессов ОС.
|
||||
[^6]: Подразумевалось обратное от «насыплем соль на рану».
|
||||
[^7]: Речь идет о самом процессе программирования: правила, соблюдение которых компилятор гарантировать не может, люди рано или поздно начнут нарушать (с плачевными последствиями). – *Прим. науч. ред.*
|
||||
[^8]: Кстати, воспользовавшись квалификатором `const`, вы сможете делиться бумажником, зная при этом, что деньги в нем защищены от воров. Стоит лишь ввести тип `shared(const(Money)*)`.
|
||||
[^9]: Возможна путаница из-за того, что Windows использует термин «критический участок» для обозначения легковесных объектов мьютексов, защищающих критические участки, а «мьютекс» – для более массивных мьютексов, с помощью которых организуется передача данных между процессами.
|
||||
[^10]: Впрочем, D разрешает объявлять синхронизированными отдельные методы класса (в том числе статические). – *Прим. науч. ред.*
|
||||
[^11]: nyukNyuk («няк-няк») – «фирменный» смех комика Керли Ховарда. – *Прим. пер.*
|
||||
[^12]: На момент выхода книги возможность вызова функций как псевдочленов (см. раздел 5.9) не была реализована полностью, и вместо кода `obj.setSameMutex(owner)` нужно было писать `setSameMutex(obj, owner)`. Возможно, все уже изменилось. – *Прим. науч. ред.*
|
||||
[^13]: Описание этой части языка не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
[^1]: Число транзисторов на кристалл будет увеличиваться вдвое каждые 24 месяца. – *Прим. пер.*
|
||||
[^2]: Далее речь идет о параллельных вычислениях в целом и не рассматриваются распараллеливание операций над векторами и другие специализированные параллельные функции ядра.
|
||||
[^3]: Что иронично, поскольку во времена классической многопоточности разделение памяти было быстрее, а обмен сообщениями – медленнее.
|
||||
[^4]: Даже заголовок раздела был изменен с «Потоки» на «Параллельные вычисления», чтобы подчеркнуть, что потоки – это не что иное, как одна из моделей параллельных вычислений.
|
||||
[^5]: Процессы языка Erlang отличаются от процессов ОС.
|
||||
[^6]: Подразумевалось обратное от «насыплем соль на рану».
|
||||
[^7]: Речь идет о самом процессе программирования: правила, соблюдение которых компилятор гарантировать не может, люди рано или поздно начнут нарушать (с плачевными последствиями). – *Прим. науч. ред.*
|
||||
[^8]: Кстати, воспользовавшись квалификатором `const`, вы сможете делиться бумажником, зная при этом, что деньги в нем защищены от воров. Стоит лишь ввести тип `shared(const(Money)*)`.
|
||||
[^9]: Возможна путаница из-за того, что Windows использует термин «критический участок» для обозначения легковесных объектов мьютексов, защищающих критические участки, а «мьютекс» – для более массивных мьютексов, с помощью которых организуется передача данных между процессами.
|
||||
[^10]: Впрочем, D разрешает объявлять синхронизированными отдельные методы класса (в том числе статические). – *Прим. науч. ред.*
|
||||
[^11]: nyukNyuk («няк-няк») – «фирменный» смех комика Керли Ховарда. – *Прим. пер.*
|
||||
[^12]: На момент выхода книги возможность вызова функций как псевдочленов (см. раздел 5.9) не была реализована полностью, и вместо кода `obj.setSameMutex(owner)` нужно было писать `setSameMutex(obj, owner)`. Возможно, все уже изменилось. – *Прим. науч. ред.*
|
||||
[^13]: Описание этой части языка не было включено в оригинал книги, но поскольку эта возможность присутствует в текущих реализациях языка, мы добавили ее описание в перевод. – *Прим. науч. ред.*
|
||||
|
|
Loading…
Reference in New Issue