Глава 2 закончена

This commit is contained in:
Alexander Zhirov 2023-01-23 00:14:13 +03:00
parent 42b2af19c0
commit 09dc3df444
18 changed files with 261 additions and 1 deletions

View File

@ -253,6 +253,8 @@ auto a = "В этой строке есть \"двойные кавычки\",
Текст умышленно перенесен на новую строку после слова `также`: строковый литерал может содержать знак перевода строки (реальное начало новой строки в исходном коде, а не комбинацию `\n`), который будет сохранен именно в этом качестве.
[Исходный код](src/chapter-2-2-5/)
[В начало ⮍](#2-2-5-строковые-литералы) [Наверх ⮍](#2-основные-типы-данных-выражения)
#### 2.2.5.1. Строковые литералы: WYSIWYG, с разделителями, строки токенов, шестнадцатеричные и импортированные
@ -321,6 +323,8 @@ auto x = import("resource.bin");
Строка, возвращаемая функцией `import`, не проверяется на соответствие кодировке UTF-8. Это сделано намеренно для реализации возможности включать двоичные данные.
[Исходный код](src/chapter-2-2-5-1/)
[В начало ⮍](#2-2-5-1-строковые-литералы-wysiwyg-с-разделителями-строки-токенов-шестнадцатеричные-и-импортированные) [Наверх ⮍](#2-основные-типы-данных-выражения)
#### 2.2.5.2. Тип строкового литерала
@ -404,6 +408,8 @@ dstring y = "Здравствуй, еще более широкий мир!"; //
Если вы хотите явно указать тип строки, то можете снабдить строковый литерал суффиксом: `c`, `w` или `d`, которые заставляют тип строкового литерала принять значение `string`, `wstring` или `dstring` соответственно.
[Исходный код](src/chapter-2-2-5-2/)
[В начало ⮍](#2-2-5-2-тип-строкового-литерала) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.2.6. Литералы массивов и ассоциативных массивов
@ -438,6 +444,8 @@ auto famousNamedConstants = [ "пи" : 3.14, "e" : 2.71, "константа д
Каждая ячейка литерала ассоциативного массива имеет вид `ключ: значение`. Тип ключей литерала ассоциативного массива вычисляется по массиву, в который неявно записываются все эти ключи, с помощью описанного выше способа. Тип значений вычисляется аналогично. После вычисления типа ключей `K` и типа значений `V` литерал типизируется как `V[K]`. Например, константа `famousNamedConstants` принимает тип `double[string]`.
[Исходный код](src/chapter-2-2-6/)
[В начало ⮍](#2-2-6-литералы-массивов-и-ассоциативных-массивов) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.2.7. Функциональные литералы
@ -480,6 +488,8 @@ assert(b == 1.5);
Теперь тип `f` `delegate double(int x)`. Все правила распознавания типа для `function` применимы без изменений к `delegate`. Отсюда справедливый вопрос: если конструкции `delegate` могут делать все, на что способны `function`-конструкции (в конце концов конструкции `delegate` *могут*, но *не обязаны* использовать переменные своего окружения), зачем же сначала возиться с функциями? Нельзя ли всегда использовать конструкции `delegate`? Ответ прост: все дело в эффективности. Очевидно, что конструкции `delegate` обладают доступом к большему количеству информации, а по непреложному закону природы за такой доступ приходится расплачиваться. На самом деле, размер `function` равен размеру указателя, а `delegate` в два раза больше (один указатель на функцию, один на окружение).
[Исходный код](src/chapter-2-2-7/)
[В начало ⮍](#2-2-7-функциональные-литералы) [Наверх ⮍](#2-основные-типы-данных-выражения)
## 2.3. Операции
@ -711,6 +721,8 @@ bool
|`shared`|`Тип`|
|`return`|Тип, возвращаемый функцией, оператором `delegate` или указателем на функцию|
[Исходный код](src/chapter-2-3-4-3/)
[В начало ⮍](#2-3-4-3-выражения-is) [Наверх ⮍](#2-основные-типы-данных-выражения)
#### 2.3.4.4. Выражения в круглых скобках
@ -759,6 +771,8 @@ assert(a == [ 0, 0, 0, 1, 3 ]); // a был изменен
Если `i > j` или `j > a.length`, генерируется исключение типа `RangeError`. Иначе если `i == j`, будет возвращен пустой массив. В качестве `arr` в выражении `arr[i .. j]` можно использовать указатель. В этом случае будет возвращен массив, отражающий область памяти начиная с адреса `arr + i` до `arr + j` (не включая элемент с адресом `arr + j`). Если `i > j`, генерируется ошибка `RangeError`, иначе при получении среза указателя границы не проверяются. И снова в некоторых режимах сборки (небезопасные итоговые сборки, см. раздел 4.1.2) все проверки границ при получении срезов могут быть отключены.
[Исходный код](src/chapter-2-3-5-5/)
[В начало ⮍](#2-3-5-5-срезы-массивов) [Наверх ⮍](#2-основные-типы-данных-выражения)
#### 2.3.5.6. Создание вложенного класса
@ -820,6 +834,8 @@ foreach (ref row; matrix)
Необязательный `адрес`, расположенный сразу после ключевого слова `new`, вводит конструкцию, называемую *новым размещением*. По смыслу вариант `new(адрес) T` отличается от других: вместо выделения памяти под новый объект происходит размещение объекта по заданному `адресу`. Такие низкоуровневые средства в обычном коде не применяются. Вы можете использовать их, например, чтобы распределять память из кучи C с помощью `malloc` и затем использовать ее для хранения значений языка D.
[Исходный код](src/chapter-2-3-6-1/)
[В начало ⮍](#2-3-6-1-выражение-new) [Наверх ⮍](#2-основные-типы-данных-выражения)
#### 2.3.6.2. Получение адреса и разыменование
@ -882,6 +898,8 @@ foreach (ref row; matrix)
Результат возведения нуля в нулевую степень единица, а в любую другую ноль.
[Исходный код](src/chapter-2-3-7/)
[В начало ⮍](#2-3-7-возведение-в-степень) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.8. Мультипликативные операции
@ -898,6 +916,8 @@ foreach (ref row; matrix)
Если такое число найти невозможно, результатом `a % b` будет особое значение NaN.
[Исходный код](src/chapter-2-3-8/)
[В начало ⮍](#2-3-8-мультипликативные-операции) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.9. Аддитивные операции
@ -950,6 +970,8 @@ auto d = a >> b; // Результат зависит от реализации
Раньше было популярно с помощью операции сдвига реализовывать быстрое целочисленное умножение на 2 (`a << 1`) или деление на 2 (`a >> 1`) или в общем случае умножение и деление на различные степени 2. Эта техника вышла из употребления, подобно видеокассетам. Пишите просто: `a * k` или `a / k`; если значение `k` известно на этапе компиляции, компилятор гарантированно сгенерирует для вас оптимальный код с операциями сдвига и всем, что еще нужно, избавив вас от волнений по поводу тонкостей работы со знаком. Не ищите сдвига на свою голову.
[Исходный код](src/chapter-2-3-10/)
[В начало ⮍](#2-3-10-сдвиг) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.11. Выражения in
@ -989,6 +1011,8 @@ else
}
```
[Исходный код](src/chapter-2-3-11/)
[В начало ⮍](#2-3-11-выражения-in) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.12. Сравнение
@ -1029,6 +1053,8 @@ void main()
Вместо выражения проверки на неравенство `!(a is b)` можно использовать его краткий вариант `a !is b`.
[Исходный код](src/chapter-2-3-12-1/)
[В начало ⮍](#2-3-12-1-проверка-на-равенство) [Наверх ⮍](#2-основные-типы-данных-выражения)
#### 2.3.12.2. Сравнение для упорядочивания
@ -1072,6 +1098,8 @@ string line;
line == "#\n" && writeln("Успешно принята строка #. ");
```
[Исходный код](src/chapter-2-3-14/)
[В начало ⮍](#2-3-14-логическое-и) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.15. Логическое ИЛИ
@ -1089,6 +1117,8 @@ string line;
line.length > 0 || line = "\n";
```
[Исходный код](src/chapter-2-3-15/)
[В начало ⮍](#2-3-15-логическое-или) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.16. Тернарная условная операция
@ -1114,6 +1144,8 @@ assert(x == 10);
Многие концептуальные примеры обобщенного программирования используют тернарную операцию сравнения для нахождения общего типа двух значений.
[Исходный код](src/chapter-2-3-16/)
[В начало ⮍](#2-3-16-тернарная-условная-операция) [Наверх ⮍](#2-основные-типы-данных-выражения)
### 2.3.17. Присваивание
@ -1138,6 +1170,8 @@ int c = (a = b, b = 7, 8);
После выполнения этого фрагмента кода переменные `a`, `b` и `c` примут значения `10`, `7` и `8` соответственно.
[Исходный код](src/chapter-2-3-18/)
[В начало ⮍](#2-3-18-выражения-с-запятой) [Наверх ⮍](#2-основные-типы-данных-выражения)
## 2.4. Итоги и справочник
@ -1170,7 +1204,7 @@ int c = (a = b, b = 7, 8);
|`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.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-срезы-массивов))|

View File

@ -0,0 +1,20 @@
import std.stdio;
void main()
{
auto a = r"Строка с \ и " ~ `"` ~ " внутри.";
auto b = r"c:\games\Sudoku.exe";
auto c = r"ab\n";
auto d = q"[Какая-то строка с "кавычками", `обратными апострофами` и [квадратными скобками]]";
auto e = q"/Просто строка/";
auto f = q"EOS
This
is a multi-line
heredoc string
EOS";
auto g = q{ foo(q{hello}); };
// auto h = q{ № };
// auto i = q{ __EOF__ };
}

View File

@ -0,0 +1,19 @@
import std.stdio;
void main()
{
writeln(typeid(typeof("Hello, world!"))); // immutable(char)[]
immutable(char)[] str = "One";
str = "Two";
writeln(typeid(typeof(str))); // immutable(char)[]
immutable(char)[3] a = "Hi!";
immutable(char)[] b = a;
writeln(a.length, " ", b.length); // 3 3
wstring x = "Здрав­ст­вуй, ши­ро­кий мир!";
writeln(typeid(typeof(x))); // immutable(wchar)[]
dstring y = "Здрав­ст­вуй, еще бо­лее ши­ро­кий мир!";
writeln(typeid(typeof(y))); // immutable(dchar)[]
}

View File

@ -0,0 +1,8 @@
import std.stdio;
void main()
{
auto crlf = "\r\n";
auto a = "В этой стро­ке есть \"двой­ные ка­выч­ки\", а так­же
пе­ре­вод стро­ки, да­же два" ~ "\n";
}

View File

@ -0,0 +1,21 @@
import std.stdio;
void main()
{
auto somePrimes = [ 2u, 3, 5, 7, 11, 13 ];
writeln(somePrimes);
auto someDoubles = [ 1.5, 3, 4.5 ];
writeln(someDoubles);
auto constants = [ 2.71, 3.14, 6.023e22 ];
writeln(constants);
constants[0] = 2.21953167;
writeln(constants);
auto salutations = [ "привет", "здравствуйте", "здорово" ];
writeln(salutations);
salutations[2] = "Да здравствует Цезарь";
writeln(salutations);
auto famousNamedConstants = [ "пи" : 3.14, "e" : 2.71, "константа дивана" : 2.22 ];
writeln(famousNamedConstants);
}

View File

@ -0,0 +1,20 @@
import std.stdio;
void main()
{
auto f = function double(int x) { return x / 10.; };
auto a = f(5);
assert(a == 0.5);
double function(int) e = function double(int x) { return x / 10.; };
auto b = e(5);
assert(b == 0.5);
int h = 2;
auto g = delegate double(int x) { return h * x / 10.; };
auto i = g(5);
assert(i == 1);
h = 3;
auto j = g(5);
assert(j == 1.5);
}

View File

@ -0,0 +1,15 @@
import std.stdio;
void main()
{
int a = -1; // То есть 0xFFFF_FFFF
int b = a << 1;
assert(b == -2); // 0xFFFF_FFFE
writeln("a = ", a, "; b = ", b, ';');
int c = a >> 1;
assert(c == -1); // 0xFFFF_FFFF
writeln("a = ", a, "; c = ", c, ';');
int d = a >>> 1;
assert(d == +2147483647); // 0x7FFF_FFFF
writeln("a = ", a, "; d = ", d, ';');
}

View File

@ -0,0 +1,20 @@
import std.stdio;
void main()
{
double[string] table = [
"one": 1.0,
"two": 2.0
];
writeln(table);
auto p = "three" in table;
if (p)
{
++*p;
}
else
{
table["three"] = 3.0;
}
writeln(table);
}

View File

@ -0,0 +1,10 @@
import std.stdio;
void main()
{
auto a = "ка­кая-то стро­ка";
auto b = a; // a и b ссы­ла­ют­ся на один и тот же мас­сив
a is b && writeln("Ага, это действительно одно и то же.");
auto c = "какая-то (другая) строка";
a is c || writeln("Действительно... не одно и то же.");
}

View File

@ -0,0 +1,7 @@
import std.stdio;
void main()
{
string line;
line == "#\n" && writeln("Успешно принята строка #. ");
}

View File

@ -0,0 +1,7 @@
import std.stdio;
void main()
{
string line;
line.length > 0 || line = "\n";
}

View File

@ -0,0 +1,9 @@
import std.stdio;
void main()
{
int x = 5, y = 5;
bool which = true;
(which ? x : y) += 5;
assert(x == 10);
}

View File

@ -0,0 +1,8 @@
import std.stdio;
void main()
{
int a = 5;
int b = 10;
int c = (a = b, b = 7, 8);
}

View File

@ -0,0 +1,22 @@
import std.stdio;
void main()
{
bool
a = is(int[]), // True, int[] до­пус­ти­мый тип
b = is(int[5]), // True, int[5] так­же до­пус­ти­мый тип
c = is(int[-3]), // False, раз­мер мас­си­ва за­дан не­вер­но
d = is(Blah); // False (ес­ли тип с име­нем Blah не был оп­ре­де­лен)
writeln("a = ", a, "; b = ", b, "; c = ", c, "; d = ", d, ';');
alias uint UInt;
assert(is(uint == UInt));
a = is(int[5] : int[]), // true, int[5] мо­жет быть пре­об­ра­зо­ван к int[]
b = is(int[5] == int[]), // false; это раз­ные ти­пы
c = is(uint : long), // true
d = is(ulong : long); // true
writeln("a = ", a, "; b = ", b, "; c = ", c, "; d = ", d, ';');
}

View File

@ -0,0 +1,10 @@
import std.stdio;
void main()
{
int[] a = new int[5]; // Соз­дать мас­сив из пя­ти це­лых чи­сел
int[] b = a[3 .. 5]; // b ссы­ла­ет­ся на два по­след­них эле­мен­та a
b[0] = 1;
b[1] = 3;
assert(a == [ 0, 0, 0, 1, 3 ]); // a был из­ме­нен
}

View File

@ -0,0 +1,16 @@
import std.stdio;
void main()
{
auto arr1 = new int[4];
assert(arr1.length == 4);
assert(arr1 == [ 0, 0, 0, 0 ]); // Ини­циа­ли­зи­ро­ван по умол­ча­нию
auto arr2 = new int[](4);
assert(arr2.length == 4);
assert(arr2 == [ 0, 0, 0, 0 ]); // Ини­циа­ли­зи­ро­ван по умол­ча­нию
auto matrix = new int[][](4, 8);
assert(matrix.length == 4);
assert(matrix[0].length == 8);
}

View File

@ -0,0 +1,7 @@
import std.stdio;
void main()
{
auto a = 2 ^^ 3;
writeln(a); // 8
}

View File

@ -0,0 +1,7 @@
import std.stdio;
void main()
{
auto a = 2 ^^ 3;
writeln(a); // 8
}