2015-12-12 09:44:12 +00:00
|
|
|
|
---
|
2015-10-14 18:10:12 +00:00
|
|
|
|
filename: learnd-ru.d
|
|
|
|
|
contributors:
|
2024-10-06 16:51:00 +00:00
|
|
|
|
- ["Anton Pastukhov", "https://anton9.com/"]
|
|
|
|
|
- ["Robert Brights-Gray", "https://lhs.su/"]
|
|
|
|
|
- ["Andre Polykanine", "https://oire.me/"]
|
2015-10-14 18:10:12 +00:00
|
|
|
|
---
|
2016-02-13 07:04:31 +00:00
|
|
|
|
|
2015-10-14 18:10:12 +00:00
|
|
|
|
D - современный компилируемый язык общего назначения с Си-подобным синтаксисом,
|
|
|
|
|
который сочетает удобство, продуманный дизайн и высокую производительность.
|
|
|
|
|
D - это С++, сделанный правильно.
|
|
|
|
|
|
2024-05-12 11:55:20 +00:00
|
|
|
|
```d
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// Welcome to D! Это однострочный комментарий
|
|
|
|
|
|
|
|
|
|
/* многострочный
|
|
|
|
|
комментарий */
|
|
|
|
|
|
|
|
|
|
/+
|
2015-12-03 12:04:28 +00:00
|
|
|
|
// вложенные комментарии
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
/* еще вложенные
|
|
|
|
|
комментарии */
|
|
|
|
|
|
|
|
|
|
/+
|
|
|
|
|
// мало уровней вложенности? Их может быть сколько угодно.
|
|
|
|
|
+/
|
|
|
|
|
+/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Имя модуля. Каждый файл с исходным кодом на D — модуль.
|
|
|
|
|
Если имя не указано явно, то предполагается, что оно совпадает с именем
|
|
|
|
|
файла. Например, для файла "test.d" имя модуля будет "test", если явно
|
|
|
|
|
не указать другое
|
|
|
|
|
*/
|
|
|
|
|
module app;
|
|
|
|
|
|
|
|
|
|
// импорт модуля. Std — пространство имен стандартной библиотеки (Phobos)
|
|
|
|
|
import std.stdio;
|
|
|
|
|
|
|
|
|
|
// можно импортировать только нужные части, не обязательно модуль целиком
|
2015-10-30 15:10:22 +00:00
|
|
|
|
import std.exception : enforce;
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
// точка входа в программу — функция main, аналогично C/C++
|
|
|
|
|
void main()
|
|
|
|
|
{
|
|
|
|
|
writeln("Hello, world!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** типы и переменные ***/
|
|
|
|
|
|
|
|
|
|
int a; // объявление переменной типа int (32 бита)
|
|
|
|
|
float b = 12.34; // тип с плавающей точкой
|
2015-12-12 09:43:56 +00:00
|
|
|
|
double c = 56.78; // тип с плавающей точкой (64 бита)
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Численные типы в D, за исключением типов с плавающей точкой и типов
|
|
|
|
|
комплексных чисел, могут быть беззнаковыми.
|
|
|
|
|
В этом случае название типа начинается с префикса "u"
|
|
|
|
|
*/
|
2015-10-30 15:10:22 +00:00
|
|
|
|
uint d = 10; ulong e = 11;
|
2015-10-14 18:10:12 +00:00
|
|
|
|
bool b = true; // логический тип
|
|
|
|
|
char d = 'd'; // UTF-символ, 8 бит. D поддерживает UTF "из коробки"
|
2015-12-12 09:43:56 +00:00
|
|
|
|
wchar e = 'é'; // символ UTF-16
|
2015-10-14 18:10:12 +00:00
|
|
|
|
dchar f; // и даже UTF-32, если он вам зачем-то понадобится
|
|
|
|
|
|
|
|
|
|
string s = "для строк есть отдельный тип, это не просто массив char-ов из Си";
|
|
|
|
|
wstring ws = "поскольку у нас есть wchar, должен быть и wstring";
|
|
|
|
|
dstring ds = "...и dstring, конечно";
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
string кириллица = "Имена переменных должны быть в Unicode, но не обязательно на латинице.";
|
|
|
|
|
|
2015-10-14 18:10:12 +00:00
|
|
|
|
typeof(a) b = 6; // typeof возвращает тип своего выражения.
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// В результате, b имеет такой же тип, как и a
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
// Тип переменной, помеченной ключевым словом auto,
|
|
|
|
|
// присваивается компилятором исходя из значения этой переменной
|
|
|
|
|
auto x = 1; // Например, тип этой переменной будет int.
|
|
|
|
|
auto y = 1.1; // этой — double
|
|
|
|
|
auto z = "Zed is dead!"; // а этой — string
|
|
|
|
|
|
|
|
|
|
int[3] arr = [1, 2, 3]; // простой одномерный массив с фиксированным размером
|
|
|
|
|
int[] arr2 = [1, 2, 3, 4]; // динамический массив
|
|
|
|
|
int[string] aa = ["key1": 5, "key2": 6]; // ассоциативный массив
|
|
|
|
|
|
|
|
|
|
/*
|
2015-12-12 09:43:56 +00:00
|
|
|
|
Строки и массивы в D — встроенные типы. Для их использования не нужно
|
2015-10-14 18:10:12 +00:00
|
|
|
|
подключать ни внешние, ни даже стандартную библиотеку, хотя в последней
|
|
|
|
|
есть множество дополнительных инструментов для работы с ними.
|
|
|
|
|
*/
|
2015-12-12 09:43:56 +00:00
|
|
|
|
immutable int ia = 10; // неизменяемый тип,
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// обозначается ключевым словом immutable
|
|
|
|
|
ia += 1; // — вызовет ошибку на этапе компиляции
|
|
|
|
|
|
|
|
|
|
// перечислимый (enumerable) тип,
|
|
|
|
|
// более правильный способ работы с константами в D
|
|
|
|
|
enum myConsts = { Const1, Const2, Const3 };
|
|
|
|
|
|
|
|
|
|
// свойства типов
|
|
|
|
|
writeln("Имя типа : ", int.stringof); // int
|
|
|
|
|
writeln("Размер в байтах : ", int.sizeof); // 4
|
|
|
|
|
writeln("Минимальное значение : ", int.min); // -2147483648
|
2015-12-12 09:43:56 +00:00
|
|
|
|
writeln("Максимальное значение : ", int.max); // 2147483647
|
2015-10-14 18:10:12 +00:00
|
|
|
|
writeln("Начальное значение : ", int.init); // 0. Это значение,
|
|
|
|
|
// присвоенное по умолчанию
|
|
|
|
|
|
|
|
|
|
// На самом деле типов в D больше, но все мы здесь описывать не будем,
|
|
|
|
|
// иначе не уложимся в Y минут.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Приведение типов ***/
|
|
|
|
|
|
|
|
|
|
// to!(имя типа)(выражение) - для большинства конверсий
|
|
|
|
|
import std.conv : to; // функция "to" - часть стандартной библиотеки, а не языка
|
|
|
|
|
double d = -1.75;
|
|
|
|
|
short s = to!short(d); // s = -1
|
|
|
|
|
|
|
|
|
|
/*
|
2015-12-12 09:43:56 +00:00
|
|
|
|
cast - если вы знаете, что делаете. Кроме того, это единственный способ
|
2015-10-14 18:10:12 +00:00
|
|
|
|
преобразования типов-указателей в "обычные" и наоборот
|
|
|
|
|
*/
|
|
|
|
|
void* v;
|
|
|
|
|
int* p = cast(int*)v;
|
|
|
|
|
|
|
|
|
|
// Для собственного удобства можно создавать псевдонимы
|
|
|
|
|
// для различных встроенных объектов
|
2015-12-12 09:43:56 +00:00
|
|
|
|
alias int newInt; // теперь можно обращаться к newInt так, как будто бы это int
|
2015-10-14 18:10:12 +00:00
|
|
|
|
newInt a = 5;
|
|
|
|
|
|
|
|
|
|
alias newInt = int; // так тоже допустимо
|
|
|
|
|
alias uint[2] pair; // дать псевдоним можно даже сложным структурам данных
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Операторы ***/
|
|
|
|
|
|
|
|
|
|
int x = 10; // присваивание
|
|
|
|
|
x = x + 1; // 11
|
|
|
|
|
x -= 2; // 9
|
|
|
|
|
x++; // 10
|
|
|
|
|
++x; // 11
|
|
|
|
|
x *= 2; // 22
|
|
|
|
|
x /= 2; // 11
|
2015-10-30 15:10:22 +00:00
|
|
|
|
x = x ^^ 2; // 121 (возведение в степень)
|
2015-10-14 18:10:12 +00:00
|
|
|
|
x ^^= 2; // 1331 (то же самое)
|
|
|
|
|
|
|
|
|
|
string str1 = "Hello";
|
|
|
|
|
string str2 = ", world!";
|
|
|
|
|
string hw = str1 ~ str2; // Конкатенация строк
|
|
|
|
|
|
|
|
|
|
int[] arr = [1, 2, 3];
|
|
|
|
|
arr ~= 4; // [1, 2, 3, 4] - добавление элемента в конец массива
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Логика и сравнения ***/
|
|
|
|
|
|
2015-10-30 15:10:22 +00:00
|
|
|
|
int x = 0; int y = 1;
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
x == y; // false
|
|
|
|
|
x > y; // false
|
|
|
|
|
x < y; // true
|
|
|
|
|
x >= y; // false
|
|
|
|
|
x != y; // true. ! — логическое "не"
|
|
|
|
|
x > 0 || x < 1; // true. || — логическое "или"
|
|
|
|
|
x > 0 && x < 1; // false && — логическое "и"
|
|
|
|
|
x ^ y // true; ^ - xor (исключающее "или")
|
|
|
|
|
|
|
|
|
|
// Тернарный оператор
|
|
|
|
|
auto y = (x > 10) ? 1 : 0; // если x больше 10, то y равен 1,
|
|
|
|
|
// в противном случае y равен нулю
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Управляющие конструкции ***/
|
|
|
|
|
|
|
|
|
|
// if - абсолютно привычен
|
|
|
|
|
if (a == 1) {
|
|
|
|
|
// ..
|
|
|
|
|
} else if (a == 2) {
|
|
|
|
|
// ..
|
|
|
|
|
} else {
|
|
|
|
|
// ..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// switch
|
|
|
|
|
switch (a) {
|
|
|
|
|
case 1:
|
|
|
|
|
// делаем что-нибудь
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
// делаем что-нибудь другое
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
// делаем что-нибудь еще
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// default обязателен, без него будет ошибка компиляции
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// в D есть констукция "final switch". Она не может содержать секцию "defaul"
|
|
|
|
|
// и применяется, когда все перечисляемые в switch варианты должны быть
|
|
|
|
|
// обработаны явным образом
|
|
|
|
|
|
|
|
|
|
int dieValue = 1;
|
|
|
|
|
final switch (dieValue) {
|
|
|
|
|
case 1:
|
|
|
|
|
writeln("You won");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2, 3, 4, 5:
|
|
|
|
|
writeln("It's a draw");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
|
writeln("I won");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// while
|
|
|
|
|
while (a > 10) {
|
|
|
|
|
// ..
|
|
|
|
|
if (number == 42) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
// бесконечный цикл
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do-while
|
|
|
|
|
do {
|
|
|
|
|
// ..
|
|
|
|
|
} while (a == 10);
|
|
|
|
|
|
|
|
|
|
// for
|
|
|
|
|
for (int number = 1; number < 11; ++number) {
|
|
|
|
|
writeln(number); // все абсолютно стандартно
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( ; ; ) {
|
|
|
|
|
// секции могут быть пустыми. Это бесконечный цикл в стиле Си
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// foreach - универсальный и самый "правильный" цикл в D
|
|
|
|
|
foreach (element; array) {
|
|
|
|
|
writeln(element); // для простых массивов
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (key, val; aa) {
|
|
|
|
|
writeln(key, ": ", val); // для ассоциативных массивов
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (c; "hello") {
|
|
|
|
|
writeln(c); // hello. Поскольку строки - это вариант массива,
|
|
|
|
|
// foreach применим и к ним
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (number; 10..15) {
|
|
|
|
|
writeln(number); // численные интервалы можно указывать явным образом
|
2015-12-12 09:46:10 +00:00
|
|
|
|
// этот цикл выведет значения с 10 по 14, но не 15,
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// поскольку диапазон не включает в себя верхнюю границу
|
2015-10-14 18:10:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// foreach_reverse - в обратную сторону
|
2015-12-12 09:43:56 +00:00
|
|
|
|
auto container = [1, 2, 3];
|
2015-10-14 18:10:12 +00:00
|
|
|
|
foreach_reverse (element; container) {
|
|
|
|
|
writefln("%s ", element); // 3, 2, 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// foreach в массивах и им подобных структурах не меняет сами структуры
|
2015-12-12 09:43:56 +00:00
|
|
|
|
int[] a = [1, 2 ,3 ,4 ,5];
|
2015-10-14 18:10:12 +00:00
|
|
|
|
foreach (elem; array) {
|
|
|
|
|
elem *= 2; // сам массив останется неизменным
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
writeln(a); // вывод: [1, 2, 3, 4, 5] Т.е изменений нет
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
// добавление ref приведет к тому, что массив будет изменяться
|
|
|
|
|
foreach (ref elem; array) {
|
2015-12-12 09:43:56 +00:00
|
|
|
|
elem *= 2;
|
2015-10-14 18:10:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
writeln(a); // [2, 4, 6, 8, 10]
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// foreach умеет рассчитывать индексы элементов
|
|
|
|
|
int[] a = [1, 2, 3, 4, 5];
|
2015-10-14 18:10:12 +00:00
|
|
|
|
foreach (ind, elem; array) {
|
|
|
|
|
writeln(ind, " ", elem); // через ind - доступен индекс элемента,
|
|
|
|
|
// а через elem - сам элемент
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Функции ***/
|
|
|
|
|
|
|
|
|
|
test(42); // Что, вот так сразу? Разве мы где-то уже объявили эту функцию?
|
|
|
|
|
|
|
|
|
|
// Нет, вот она. Это не Си, здесь объявление функции не обязательно должно быть
|
|
|
|
|
// до первого вызова
|
|
|
|
|
int test(int argument) {
|
|
|
|
|
return argument * 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// В D используется единый синтаксис вызова функций
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// (UFCS, Uniform Function Call Syntax), поэтому так тоже можно:
|
|
|
|
|
int var = 42.test();
|
|
|
|
|
|
|
|
|
|
// и даже так, если у функции нет аргументов:
|
|
|
|
|
int var2 = 42.test;
|
|
|
|
|
|
|
|
|
|
// можно выстраивать цепочки:
|
|
|
|
|
int var3 = 42.test.test;
|
|
|
|
|
|
|
|
|
|
/*
|
2015-12-12 09:43:56 +00:00
|
|
|
|
Аргументы в функцию передаются по значению (т.е. функция работает не с
|
2015-10-14 18:10:12 +00:00
|
|
|
|
оригинальными значениями, переданными ей, а с их локальными копиями.
|
|
|
|
|
Исключение составляют объекты классов, которые передаются по ссылке.
|
|
|
|
|
Кроме того, любой параметр можно передать в функцию по ссылке с помощью
|
2015-12-12 09:43:56 +00:00
|
|
|
|
ключевого слова "ref"
|
2015-10-14 18:10:12 +00:00
|
|
|
|
*/
|
|
|
|
|
int var = 10;
|
|
|
|
|
|
|
|
|
|
void fn1(int arg) {
|
|
|
|
|
arg += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void fn2(ref int arg) {
|
|
|
|
|
arg += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn1(var); // var все еще = 10
|
|
|
|
|
fn2(var); // теперь var = 11
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// Возвращаемое значение тоже может быть auto,
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// если его можно "угадать" из контекста
|
|
|
|
|
auto add(int x, int y) {
|
|
|
|
|
return x + y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto z = add(x, y); // тип int - компилятор вывел его автоматически
|
|
|
|
|
|
|
|
|
|
// Значения аргументов по умолчанию
|
|
|
|
|
float linearFunction(float k, float x, float b = 1)
|
|
|
|
|
{
|
|
|
|
|
return k * x + b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto linear1 = linearFunction(0.5, 2, 3); // все аргументы используются
|
|
|
|
|
auto linear2 = linearFunction(0.5, 2); // один аргумент пропущен, но в функции
|
|
|
|
|
// он все равно использован и равен 1
|
|
|
|
|
|
|
|
|
|
// допускается описание вложенных функций
|
|
|
|
|
float quarter(float x) {
|
|
|
|
|
float doubled(float y) {
|
|
|
|
|
return y * y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return doubled(doubled(x));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// функции с переменным числом аргументов
|
|
|
|
|
int sum(int[] a...)
|
|
|
|
|
{
|
|
|
|
|
int s = 0;
|
|
|
|
|
foreach (elem; a) {
|
|
|
|
|
s += elem;
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto sum1 = sum(1);
|
|
|
|
|
auto sum2 = sum(1,2,3,4);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
модификатор "in" перед аргументами функций говорит о том, что функция имеет
|
|
|
|
|
право их только просматривать. При попытке модификации такого аргумента
|
|
|
|
|
внутри функции - получите ошибку
|
|
|
|
|
*/
|
|
|
|
|
float printFloat(in float a)
|
|
|
|
|
{
|
|
|
|
|
writeln(a);
|
|
|
|
|
}
|
|
|
|
|
printFloat(a); // использование таких функций - самое обычное
|
|
|
|
|
|
|
|
|
|
// модификатор "out" позволяет вернуть из функции несколько результатов
|
|
|
|
|
// без посредства глобальных переменных или массивов
|
|
|
|
|
uint remMod(uint a, uint b, out uint modulus)
|
|
|
|
|
{
|
2015-12-12 09:43:56 +00:00
|
|
|
|
uint remainder = a / b;
|
2015-10-14 18:10:12 +00:00
|
|
|
|
modulus = a % b;
|
|
|
|
|
return remainder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint modulus; // пока в этой переменной ноль
|
2015-12-12 09:43:56 +00:00
|
|
|
|
uint rem = remMod(5, 2, modulus); // наша "хитрая" функция, и теперь
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// в modulus - остаток от деления
|
|
|
|
|
writeln(rem, " ", modulus); // вывод: 2 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Структуры, классы, базовое ООП ***/
|
|
|
|
|
|
|
|
|
|
// Объявление структуры. Структуры почти как в Си
|
|
|
|
|
struct MyStruct {
|
|
|
|
|
int a;
|
|
|
|
|
float b;
|
|
|
|
|
|
|
|
|
|
void multiply() {
|
|
|
|
|
return a * b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MyStruct str1; // Объявление переменной с типом MyStruct
|
|
|
|
|
str1.a = 10; // Обращение к полю
|
|
|
|
|
str1.b = 20;
|
2015-12-12 09:43:56 +00:00
|
|
|
|
auto result = str1.multiply();
|
|
|
|
|
MyStruct str2 = {4, 8} // Объявление + инициализация в стиле Си
|
|
|
|
|
auto str3 = MyStruct(5, 10); // Объявление + инициализация в стиле D
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// области видимости полей и методов - 3 способа задания
|
|
|
|
|
struct MyStruct2 {
|
|
|
|
|
public int a;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
float b;
|
|
|
|
|
bool c;
|
|
|
|
|
|
|
|
|
|
protected {
|
|
|
|
|
float multiply() {
|
|
|
|
|
return a * b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
в дополнение к знакомым public, private и protected, в D есть еще
|
2015-12-12 09:43:56 +00:00
|
|
|
|
область видимости "package". Поля и методы с этим атрибутом будут
|
2015-10-14 18:10:12 +00:00
|
|
|
|
доступны изо всех модулей, включенных в "пакет" (package), но не
|
|
|
|
|
за его пределами. package - это "папка", в которой может храниться
|
|
|
|
|
несколько модулей. Например, в "import.std.stdio", "std" - это
|
|
|
|
|
package, в котором есть модуль stdio (и еще множество других)
|
|
|
|
|
*/
|
|
|
|
|
package:
|
|
|
|
|
string d;
|
2015-12-12 09:43:56 +00:00
|
|
|
|
|
|
|
|
|
/* помимо этого, имеется еще один модификатор - export, который позволяет
|
2015-10-14 18:10:12 +00:00
|
|
|
|
использовать объявленный с ним идентификатор даже вне самой программы !
|
|
|
|
|
*/
|
|
|
|
|
export:
|
|
|
|
|
string description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Конструкторы и деструкторы
|
|
|
|
|
struct MyStruct3 {
|
|
|
|
|
this() { // конструктор. Для структур его не обязательно указывать явно,
|
|
|
|
|
// в этом случае пустой конструктор добавляется компилятором
|
|
|
|
|
writeln("Hello, world!");
|
|
|
|
|
}
|
2015-12-12 09:43:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// а вот это конструкция - одна из интересных идиом и представляет собой
|
|
|
|
|
// конструктор копирования, т.е конструктор, возвращающий копию структуры.
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// Работает только в структурах.
|
|
|
|
|
this(this)
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~this() { // деструктор, также необязателен
|
|
|
|
|
writeln("Awww!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Объявление простейшего класса
|
|
|
|
|
class MyClass {
|
|
|
|
|
int a; // в D по умолчанию данные-члены являются public
|
|
|
|
|
float b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto mc = new MyClass(); // ...и создание его экземпляра
|
|
|
|
|
auto mc2 = new MyClass; // ... тоже сработает
|
|
|
|
|
|
|
|
|
|
// Конструктор
|
|
|
|
|
class MyClass2 {
|
|
|
|
|
int a;
|
|
|
|
|
float b;
|
|
|
|
|
|
|
|
|
|
this(int a, float b) {
|
|
|
|
|
this.a = a; // ключевое слово "this" - ссылка на объект класса
|
|
|
|
|
this.b = b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto mc2 = new MyClass2(1, 2.3);
|
|
|
|
|
|
|
|
|
|
// Классы могут быть вложенными
|
|
|
|
|
class Outer
|
|
|
|
|
{
|
|
|
|
|
int m;
|
|
|
|
|
|
|
|
|
|
class Inner
|
|
|
|
|
{
|
|
|
|
|
int foo()
|
|
|
|
|
{
|
2015-12-12 09:43:56 +00:00
|
|
|
|
return m; // можно обращаться к полям "внешнего" класса
|
2015-10-14 18:10:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// наследование
|
|
|
|
|
class Base {
|
|
|
|
|
int a = 1;
|
|
|
|
|
float b = 2.34;
|
2015-12-12 09:43:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// это статический метод, т.е метод который можно вызывать, обращаясь
|
|
|
|
|
// к классу напрямую, а не через создание экземпляра объекта
|
2015-10-14 18:10:12 +00:00
|
|
|
|
static void multiply(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
writeln(x * y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Base.multiply(2, 5); // используем статический метод. Результат: 10
|
|
|
|
|
|
|
|
|
|
class Derived : Base {
|
|
|
|
|
string c = "Поле класса - наследника";
|
2015-12-12 09:43:56 +00:00
|
|
|
|
|
|
|
|
|
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// override означает то, что наследник предоставит свою реализацию метода,
|
|
|
|
|
// переопределив метод базового класса
|
|
|
|
|
override static void multiply(int x, int y)
|
|
|
|
|
{
|
2015-12-12 09:43:56 +00:00
|
|
|
|
super.multiply(x, y); // super - это ссылка на класс-предок, или базовый класс
|
2015-10-14 18:10:12 +00:00
|
|
|
|
writeln(x * y * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto mc3 = new Derived();
|
|
|
|
|
writeln(mc3.a); // 1
|
|
|
|
|
writeln(mc3.b); // 2.34
|
|
|
|
|
writeln(mc3.c); // Поле класса - наследника
|
|
|
|
|
|
|
|
|
|
// Финальный класс, наследовать от него нельзя
|
|
|
|
|
// кроме того, модификатор final работает не только для классов, но и для методов
|
|
|
|
|
// и даже для модулей !
|
|
|
|
|
final class FC {
|
|
|
|
|
int a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Derived : FC { // это вызовет ошибку
|
|
|
|
|
float b;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
// Абстрактный класс не может быть истанциирован, но может иметь наследников
|
2015-10-14 18:10:12 +00:00
|
|
|
|
abstract class AC {
|
|
|
|
|
int a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto ac = new AC(); // это вызовет ошибку
|
|
|
|
|
|
|
|
|
|
class Implementation : AC {
|
|
|
|
|
float b;
|
2015-12-12 09:43:56 +00:00
|
|
|
|
|
|
|
|
|
// final перед методом нефинального класса означает запрет возможности
|
2015-10-14 18:10:12 +00:00
|
|
|
|
// переопределения метода
|
|
|
|
|
final void test()
|
|
|
|
|
{
|
|
|
|
|
writeln("test passed !");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto impl = new Implementation(); // ОК
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
/*** Примеси (mixins) ***/
|
2015-10-14 18:10:12 +00:00
|
|
|
|
|
|
|
|
|
// В D можно вставлять код как строку, если эта строка известна на этапе
|
|
|
|
|
// компиляции. Например:
|
|
|
|
|
void main() {
|
|
|
|
|
mixin(`writeln("Hello World!");`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// еще пример
|
|
|
|
|
string print(string s) {
|
|
|
|
|
return `writeln("` ~ s ~ `");`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
mixin (print("str1"));
|
|
|
|
|
mixin (print("str2"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Шаблоны ***/
|
|
|
|
|
|
|
|
|
|
/*
|
2015-12-12 09:43:56 +00:00
|
|
|
|
Шаблон функции. Эта функция принимает аргументы разных типов, которые
|
|
|
|
|
подставляются вместо T на этапе компиляции. "T" - это не специальный
|
2015-10-14 18:10:12 +00:00
|
|
|
|
символ, а просто буква. Вместо "T" может быть любое слово, кроме ключевого.
|
|
|
|
|
*/
|
|
|
|
|
void print(T)(T value) {
|
|
|
|
|
writefln("%s", value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
print(42); // В одну и ту же функцию передается: целое
|
|
|
|
|
print(1.2); // ...число с плавающей точкой,
|
|
|
|
|
print("test"); // ...строка
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "Шаблонных" параметров может быть сколько угодно
|
|
|
|
|
void print(T1, T2)(T1 value1, T2 value2) {
|
|
|
|
|
writefln(" %s %s", value1, value2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
print(42, "Test");
|
|
|
|
|
print(1.2, 33);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Шаблон класса
|
|
|
|
|
class Stack(T)
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
T[] elements;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
void push(T element) {
|
|
|
|
|
elements ~= element;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pop() {
|
|
|
|
|
--elements.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T top() const @property {
|
|
|
|
|
return elements[$ - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t length() const @property {
|
|
|
|
|
return elements.length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
/*
|
2015-12-12 09:43:56 +00:00
|
|
|
|
восклицательный знак - признак шаблона. В данном случае мы создаем
|
|
|
|
|
класс и указываем, что "шаблонное" поле будет иметь тип string
|
2015-10-14 18:10:12 +00:00
|
|
|
|
*/
|
|
|
|
|
auto stack = new Stack!string;
|
|
|
|
|
|
|
|
|
|
stack.push("Test1");
|
|
|
|
|
stack.push("Test2");
|
|
|
|
|
|
|
|
|
|
writeln(stack.top);
|
|
|
|
|
writeln(stack.length);
|
|
|
|
|
|
|
|
|
|
stack.pop;
|
|
|
|
|
writeln(stack.top);
|
|
|
|
|
writeln(stack.length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Диапазоны (ranges) ***/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Диапазоны - это абстракция, которая позволяет легко использовать разные
|
|
|
|
|
алгоритмы с разными структурами данных. Вместо того, чтобы определять свои
|
|
|
|
|
уникальные алгоритмы для каждой структуры, мы можем просто указать для нее
|
|
|
|
|
несколько единообразных функций, определяющих, _как_ мы получаем доступ
|
|
|
|
|
к элементам контейнера, вместо того, чтобы описывать внутреннее устройство
|
|
|
|
|
этого контейнера. Сложно? На самом деле не очень.
|
|
|
|
|
|
|
|
|
|
Простейший вид диапазона - Input Range. Для того, чтобы превратить любой
|
|
|
|
|
контейнер в Input Range, достаточно реализовать для него 3 метода:
|
|
|
|
|
- empty - проверяет, пуст ли контейнер
|
|
|
|
|
- front - дает доступ к первому элементу контейнера
|
|
|
|
|
- popFront - удаляет из контейнера первый элемент
|
|
|
|
|
*/
|
|
|
|
|
struct Student
|
|
|
|
|
{
|
|
|
|
|
string name;
|
|
|
|
|
int number;
|
|
|
|
|
string toString() {
|
|
|
|
|
return format("%s(%s)", name, number);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct School
|
|
|
|
|
{
|
|
|
|
|
Student[] students;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct StudentRange
|
|
|
|
|
{
|
|
|
|
|
Student[] students;
|
|
|
|
|
|
|
|
|
|
this(School school) {
|
|
|
|
|
this.students = school.students;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool empty() {
|
|
|
|
|
return students.length == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-12 09:47:02 +00:00
|
|
|
|
Student front() {
|
2015-10-14 18:10:12 +00:00
|
|
|
|
return students[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void popFront() {
|
|
|
|
|
students = students[1 .. $];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main(){
|
|
|
|
|
auto school = School([
|
2015-12-12 09:43:56 +00:00
|
|
|
|
Student("Mike", 1),
|
|
|
|
|
Student("John", 2) ,
|
2015-10-14 18:10:12 +00:00
|
|
|
|
Student("Dan", 3)
|
|
|
|
|
]);
|
|
|
|
|
auto range = StudentRange(school);
|
|
|
|
|
writeln(range); // [Mike(1), John(2), Dan(3)]
|
|
|
|
|
writeln(school.students.length); // 3
|
|
|
|
|
writeln(range.front()); // Mike(1)
|
|
|
|
|
range.popFront();
|
|
|
|
|
writeln(range.empty()); // false
|
|
|
|
|
writeln(range); // [John(2), Dan(3)]
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Смысл в том, что нам не так уж важно внутреннее устройство контейнера, если
|
|
|
|
|
у нас есть унифицированные методы доступа к его элементам.
|
|
|
|
|
Кроме Input Range в D есть и другие типы диапазонов, которые требуют
|
|
|
|
|
реализации большего числа методов, зато дают больше контроля. Это большая
|
|
|
|
|
тема и мы не будем в подробностях освещать ее здесь.
|
|
|
|
|
|
|
|
|
|
Диапазоны - это важная часть D, они используются в нем повсеместно.
|
|
|
|
|
*/
|
|
|
|
|
```
|
2024-04-06 15:33:50 +00:00
|
|
|
|
|
2015-10-14 18:10:12 +00:00
|
|
|
|
## Что дальше?
|
|
|
|
|
|
2015-12-12 09:43:56 +00:00
|
|
|
|
- [Официальный сайт](http://dlang.org/)
|
|
|
|
|
- [Онлайн-книга](http://ddili.org/ders/d.en/)
|
|
|
|
|
- [Официальная вики](http://wiki.dlang.org/)
|