mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
Update d-ru.html.markdown
This commit is contained in:
parent
b9cde57bc7
commit
f854fe1111
@ -1,16 +1,17 @@
|
|||||||
---
|
/*---
|
||||||
language: d
|
language: d
|
||||||
filename: learnd-ru.d
|
filename: learnd-ru.d
|
||||||
contributors:
|
contributors:
|
||||||
- ["Anton Pastukhov", "http://dprogramming.ru/"]
|
- ["Anton Pastukhov", "http://dprogramming.ru/"]
|
||||||
- ["Robert Brights-Gray", "http://lhs-blog.info/"]
|
- ["Robert Brights-Gray", "http://lhs-blog.info/"]
|
||||||
|
- ["Andre Polykanine", "http://oire.me/"]
|
||||||
lang: ru-ru
|
lang: ru-ru
|
||||||
---
|
---
|
||||||
D - современный компилируемый язык общего назначения с Си-подобным синтаксисом,
|
D - современный компилируемый язык общего назначения с Си-подобным синтаксисом,
|
||||||
который сочетает удобство, продуманный дизайн и высокую производительность.
|
который сочетает удобство, продуманный дизайн и высокую производительность.
|
||||||
D - это С++, сделанный правильно.
|
D - это С++, сделанный правильно.
|
||||||
|
|
||||||
```d
|
```d */
|
||||||
// Welcome to D! Это однострочный комментарий
|
// Welcome to D! Это однострочный комментарий
|
||||||
|
|
||||||
/* многострочный
|
/* многострочный
|
||||||
@ -53,7 +54,7 @@ void main()
|
|||||||
|
|
||||||
int a; // объявление переменной типа int (32 бита)
|
int a; // объявление переменной типа int (32 бита)
|
||||||
float b = 12.34; // тип с плавающей точкой
|
float b = 12.34; // тип с плавающей точкой
|
||||||
double с = 56.78; // тип с плавающей точкой (64 бита)
|
double c = 56.78; // тип с плавающей точкой (64 бита)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Численные типы в D, за исключением типов с плавающей точкой и типов
|
Численные типы в D, за исключением типов с плавающей точкой и типов
|
||||||
@ -63,15 +64,17 @@ double с = 56.78; // тип с плавающей точкой (64 бита)
|
|||||||
uint d = 10; ulong e = 11;
|
uint d = 10; ulong e = 11;
|
||||||
bool b = true; // логический тип
|
bool b = true; // логический тип
|
||||||
char d = 'd'; // UTF-символ, 8 бит. D поддерживает UTF "из коробки"
|
char d = 'd'; // UTF-символ, 8 бит. D поддерживает UTF "из коробки"
|
||||||
wchar = 'é'; // символ UTF-16
|
wchar e = 'é'; // символ UTF-16
|
||||||
dchar f; // и даже UTF-32, если он вам зачем-то понадобится
|
dchar f; // и даже UTF-32, если он вам зачем-то понадобится
|
||||||
|
|
||||||
string s = "для строк есть отдельный тип, это не просто массив char-ов из Си";
|
string s = "для строк есть отдельный тип, это не просто массив char-ов из Си";
|
||||||
wstring ws = "поскольку у нас есть wchar, должен быть и wstring";
|
wstring ws = "поскольку у нас есть wchar, должен быть и wstring";
|
||||||
dstring ds = "...и dstring, конечно";
|
dstring ds = "...и dstring, конечно";
|
||||||
|
|
||||||
|
string кириллица = "Имена переменных должны быть в Unicode, но не обязательно на латинице.";
|
||||||
|
|
||||||
typeof(a) b = 6; // typeof возвращает тип своего выражения.
|
typeof(a) b = 6; // typeof возвращает тип своего выражения.
|
||||||
// В результате, b имеет такой же тип как и a
|
// В результате, b имеет такой же тип, как и a
|
||||||
|
|
||||||
// Тип переменной, помеченной ключевым словом auto,
|
// Тип переменной, помеченной ключевым словом auto,
|
||||||
// присваивается компилятором исходя из значения этой переменной
|
// присваивается компилятором исходя из значения этой переменной
|
||||||
@ -84,11 +87,11 @@ int[] arr2 = [1, 2, 3, 4]; // динамический массив
|
|||||||
int[string] aa = ["key1": 5, "key2": 6]; // ассоциативный массив
|
int[string] aa = ["key1": 5, "key2": 6]; // ассоциативный массив
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cтроки и массивы в D — встроенные типы. Для их использования не нужно
|
Строки и массивы в D — встроенные типы. Для их использования не нужно
|
||||||
подключать ни внешние, ни даже стандартную библиотеку, хотя в последней
|
подключать ни внешние, ни даже стандартную библиотеку, хотя в последней
|
||||||
есть множество дополнительных инструментов для работы с ними.
|
есть множество дополнительных инструментов для работы с ними.
|
||||||
*/
|
*/
|
||||||
immutalbe int ia = 10; // неизменяемый тип,
|
immutable int ia = 10; // неизменяемый тип,
|
||||||
// обозначается ключевым словом immutable
|
// обозначается ключевым словом immutable
|
||||||
ia += 1; // — вызовет ошибку на этапе компиляции
|
ia += 1; // — вызовет ошибку на этапе компиляции
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ enum myConsts = { Const1, Const2, Const3 };
|
|||||||
writeln("Имя типа : ", int.stringof); // int
|
writeln("Имя типа : ", int.stringof); // int
|
||||||
writeln("Размер в байтах : ", int.sizeof); // 4
|
writeln("Размер в байтах : ", int.sizeof); // 4
|
||||||
writeln("Минимальное значение : ", int.min); // -2147483648
|
writeln("Минимальное значение : ", int.min); // -2147483648
|
||||||
writeln("Максимальное значениеe : ", int.max); // 2147483647
|
writeln("Максимальное значение : ", int.max); // 2147483647
|
||||||
writeln("Начальное значение : ", int.init); // 0. Это значение,
|
writeln("Начальное значение : ", int.init); // 0. Это значение,
|
||||||
// присвоенное по умолчанию
|
// присвоенное по умолчанию
|
||||||
|
|
||||||
@ -111,17 +114,13 @@ writeln("Начальное значение : ", int.init); // 0. Эт
|
|||||||
|
|
||||||
/*** Приведение типов ***/
|
/*** Приведение типов ***/
|
||||||
|
|
||||||
// Простейший вариант
|
|
||||||
int i;
|
|
||||||
double j = double(i) / 2;
|
|
||||||
|
|
||||||
// to!(имя типа)(выражение) - для большинства конверсий
|
// to!(имя типа)(выражение) - для большинства конверсий
|
||||||
import std.conv : to; // функция "to" - часть стандартной библиотеки, а не языка
|
import std.conv : to; // функция "to" - часть стандартной библиотеки, а не языка
|
||||||
double d = -1.75;
|
double d = -1.75;
|
||||||
short s = to!short(d); // s = -1
|
short s = to!short(d); // s = -1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
cast - если вы знаете, что делаете. Кроме того, это единственный способ
|
cast - если вы знаете, что делаете. Кроме того, это единственный способ
|
||||||
преобразования типов-указателей в "обычные" и наоборот
|
преобразования типов-указателей в "обычные" и наоборот
|
||||||
*/
|
*/
|
||||||
void* v;
|
void* v;
|
||||||
@ -129,7 +128,7 @@ int* p = cast(int*)v;
|
|||||||
|
|
||||||
// Для собственного удобства можно создавать псевдонимы
|
// Для собственного удобства можно создавать псевдонимы
|
||||||
// для различных встроенных объектов
|
// для различных встроенных объектов
|
||||||
alias int newInt; // теперь можно обращаться к int так, как будто бы это newInt
|
alias int newInt; // теперь можно обращаться к newInt так, как будто бы это int
|
||||||
newInt a = 5;
|
newInt a = 5;
|
||||||
|
|
||||||
alias newInt = int; // так тоже допустимо
|
alias newInt = int; // так тоже допустимо
|
||||||
@ -203,6 +202,25 @@ switch (a) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// в 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;
|
||||||
|
}
|
||||||
|
|
||||||
// while
|
// while
|
||||||
while (a > 10) {
|
while (a > 10) {
|
||||||
// ..
|
// ..
|
||||||
@ -245,31 +263,33 @@ foreach (c; "hello") {
|
|||||||
|
|
||||||
foreach (number; 10..15) {
|
foreach (number; 10..15) {
|
||||||
writeln(number); // численные интервалы можно указывать явным образом
|
writeln(number); // численные интервалы можно указывать явным образом
|
||||||
|
// этот цикл выведет значения с 10 по 15, но не 15,
|
||||||
|
// поскольку диапазон не включает в себя верхнюю границу
|
||||||
}
|
}
|
||||||
|
|
||||||
// foreach_reverse - в обратную сторону
|
// foreach_reverse - в обратную сторону
|
||||||
auto container = [ 1, 2, 3 ];
|
auto container = [1, 2, 3];
|
||||||
foreach_reverse (element; container) {
|
foreach_reverse (element; container) {
|
||||||
writefln("%s ", element); // 3, 2, 1
|
writefln("%s ", element); // 3, 2, 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// foreach в массивах и им подобных структурах не меняет сами структуры
|
// foreach в массивах и им подобных структурах не меняет сами структуры
|
||||||
int[] a = [1,2,3,4,5];
|
int[] a = [1, 2 ,3 ,4 ,5];
|
||||||
foreach (elem; array) {
|
foreach (elem; array) {
|
||||||
elem *= 2; // сам массив останется неизменным
|
elem *= 2; // сам массив останется неизменным
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln(a); // вывод: [1,2,3,4,5] Т.е изменений нет
|
writeln(a); // вывод: [1, 2, 3, 4, 5] Т.е изменений нет
|
||||||
|
|
||||||
// добавление ref приведет к тому, что массив будет изменяться
|
// добавление ref приведет к тому, что массив будет изменяться
|
||||||
foreach (ref elem; array) {
|
foreach (ref elem; array) {
|
||||||
elem *= 2; // сам массив останется неизменным
|
elem *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln(a); // [2,4,6,8,10]
|
writeln(a); // [2, 4, 6, 8, 10]
|
||||||
|
|
||||||
// foreach умеет расчитывать индексы элементов
|
// foreach умеет рассчитывать индексы элементов
|
||||||
int[] a = [1,2,3,4,5];
|
int[] a = [1, 2, 3, 4, 5];
|
||||||
foreach (ind, elem; array) {
|
foreach (ind, elem; array) {
|
||||||
writeln(ind, " ", elem); // через ind - доступен индекс элемента,
|
writeln(ind, " ", elem); // через ind - доступен индекс элемента,
|
||||||
// а через elem - сам элемент
|
// а через elem - сам элемент
|
||||||
@ -288,7 +308,7 @@ int test(int argument) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// В D используется унифицированныйй синтаксис вызова функций
|
// В D используется единый синтаксис вызова функций
|
||||||
// (UFCS, Uniform Function Call Syntax), поэтому так тоже можно:
|
// (UFCS, Uniform Function Call Syntax), поэтому так тоже можно:
|
||||||
int var = 42.test();
|
int var = 42.test();
|
||||||
|
|
||||||
@ -299,11 +319,11 @@ int var2 = 42.test;
|
|||||||
int var3 = 42.test.test;
|
int var3 = 42.test.test;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Аргументы в функцию передаются по значению (т. е. функция работает не с
|
Аргументы в функцию передаются по значению (т.е. функция работает не с
|
||||||
оригинальными значениями, переданными ей, а с их локальными копиями.
|
оригинальными значениями, переданными ей, а с их локальными копиями.
|
||||||
Исключение составляют объекты классов, которые передаются по ссылке.
|
Исключение составляют объекты классов, которые передаются по ссылке.
|
||||||
Кроме того, любой параметр можно передать в функцию по ссылке с помощью
|
Кроме того, любой параметр можно передать в функцию по ссылке с помощью
|
||||||
ключевого слова ref
|
ключевого слова "ref"
|
||||||
*/
|
*/
|
||||||
int var = 10;
|
int var = 10;
|
||||||
|
|
||||||
@ -318,7 +338,7 @@ void fn2(ref int arg) {
|
|||||||
fn1(var); // var все еще = 10
|
fn1(var); // var все еще = 10
|
||||||
fn2(var); // теперь var = 11
|
fn2(var); // теперь var = 11
|
||||||
|
|
||||||
// Возвращаемое значение тоже может быть auto,
|
// Возвращаемое значение тоже может быть auto,
|
||||||
// если его можно "угадать" из контекста
|
// если его можно "угадать" из контекста
|
||||||
auto add(int x, int y) {
|
auto add(int x, int y) {
|
||||||
return x + y;
|
return x + y;
|
||||||
@ -373,13 +393,13 @@ printFloat(a); // использование таких функций - сам
|
|||||||
// без посредства глобальных переменных или массивов
|
// без посредства глобальных переменных или массивов
|
||||||
uint remMod(uint a, uint b, out uint modulus)
|
uint remMod(uint a, uint b, out uint modulus)
|
||||||
{
|
{
|
||||||
uint remainder = a / b;
|
uint remainder = a / b;
|
||||||
modulus = a % b;
|
modulus = a % b;
|
||||||
return remainder;
|
return remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint modulus; // пока в этой переменной ноль
|
uint modulus; // пока в этой переменной ноль
|
||||||
uint rem = remMod(5,2,modulus); // наша "хитрая" функция, и теперь,
|
uint rem = remMod(5, 2, modulus); // наша "хитрая" функция, и теперь
|
||||||
// в modulus - остаток от деления
|
// в modulus - остаток от деления
|
||||||
writeln(rem, " ", modulus); // вывод: 2 1
|
writeln(rem, " ", modulus); // вывод: 2 1
|
||||||
|
|
||||||
@ -400,9 +420,9 @@ struct MyStruct {
|
|||||||
MyStruct str1; // Объявление переменной с типом MyStruct
|
MyStruct str1; // Объявление переменной с типом MyStruct
|
||||||
str1.a = 10; // Обращение к полю
|
str1.a = 10; // Обращение к полю
|
||||||
str1.b = 20;
|
str1.b = 20;
|
||||||
auto result = str1.multiply();
|
auto result = str1.multiply();
|
||||||
MyStruct str2 = {4, 8} // Объявление + инициальзация в стиле Си
|
MyStruct str2 = {4, 8} // Объявление + инициализация в стиле Си
|
||||||
auto str3 = MyStruct(5, 10); // Объявление + инициальзация в стиле D
|
auto str3 = MyStruct(5, 10); // Объявление + инициализация в стиле D
|
||||||
|
|
||||||
|
|
||||||
// области видимости полей и методов - 3 способа задания
|
// области видимости полей и методов - 3 способа задания
|
||||||
@ -420,7 +440,7 @@ struct MyStruct2 {
|
|||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
в дополнение к знакомым public, private и protected, в D есть еще
|
в дополнение к знакомым public, private и protected, в D есть еще
|
||||||
область видимости "package". Поля и методы с этим атрибутам будут
|
область видимости "package". Поля и методы с этим атрибутом будут
|
||||||
доступны изо всех модулей, включенных в "пакет" (package), но не
|
доступны изо всех модулей, включенных в "пакет" (package), но не
|
||||||
за его пределами. package - это "папка", в которой может храниться
|
за его пределами. package - это "папка", в которой может храниться
|
||||||
несколько модулей. Например, в "import.std.stdio", "std" - это
|
несколько модулей. Например, в "import.std.stdio", "std" - это
|
||||||
@ -428,8 +448,8 @@ struct MyStruct2 {
|
|||||||
*/
|
*/
|
||||||
package:
|
package:
|
||||||
string d;
|
string d;
|
||||||
|
|
||||||
/* помимо этого, имеется еще один модификатор - export, который позволяет
|
/* помимо этого, имеется еще один модификатор - export, который позволяет
|
||||||
использовать объявленный с ним идентификатор даже вне самой программы !
|
использовать объявленный с ним идентификатор даже вне самой программы !
|
||||||
*/
|
*/
|
||||||
export:
|
export:
|
||||||
@ -442,10 +462,10 @@ struct MyStruct3 {
|
|||||||
// в этом случае пустой конструктор добавляется компилятором
|
// в этом случае пустой конструктор добавляется компилятором
|
||||||
writeln("Hello, world!");
|
writeln("Hello, world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// а вот это конструкция, одна из интересных идиом и представлет собой
|
// а вот это конструкция - одна из интересных идиом и представляет собой
|
||||||
// конструктор копирования, т.е конструктор возвращающий копию структуры.
|
// конструктор копирования, т.е конструктор, возвращающий копию структуры.
|
||||||
// Работает только в структурах.
|
// Работает только в структурах.
|
||||||
this(this)
|
this(this)
|
||||||
{
|
{
|
||||||
@ -488,7 +508,7 @@ class Outer
|
|||||||
{
|
{
|
||||||
int foo()
|
int foo()
|
||||||
{
|
{
|
||||||
return m; // можно обращаться к полям "родительского" класса
|
return m; // можно обращаться к полям "внешнего" класса
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,10 +517,10 @@ class Outer
|
|||||||
class Base {
|
class Base {
|
||||||
int a = 1;
|
int a = 1;
|
||||||
float b = 2.34;
|
float b = 2.34;
|
||||||
|
|
||||||
|
|
||||||
// это статический метод, т.е метод который можно вызывать обращаясь
|
// это статический метод, т.е метод который можно вызывать, обращаясь
|
||||||
// классу напрямую, а не через создание экземпляра объекта
|
// к классу напрямую, а не через создание экземпляра объекта
|
||||||
static void multiply(int x, int y)
|
static void multiply(int x, int y)
|
||||||
{
|
{
|
||||||
writeln(x * y);
|
writeln(x * y);
|
||||||
@ -511,13 +531,13 @@ Base.multiply(2, 5); // используем статический метод.
|
|||||||
|
|
||||||
class Derived : Base {
|
class Derived : Base {
|
||||||
string c = "Поле класса - наследника";
|
string c = "Поле класса - наследника";
|
||||||
|
|
||||||
|
|
||||||
// override означает то, что наследник предоставит свою реализацию метода,
|
// override означает то, что наследник предоставит свою реализацию метода,
|
||||||
// переопределив метод базового класса
|
// переопределив метод базового класса
|
||||||
override static void multiply(int x, int y)
|
override static void multiply(int x, int y)
|
||||||
{
|
{
|
||||||
super.multiply(x, y); // super - это ссылка на класс-предок или базовый класс
|
super.multiply(x, y); // super - это ссылка на класс-предок, или базовый класс
|
||||||
writeln(x * y * 2);
|
writeln(x * y * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,7 +558,7 @@ class Derived : FC { // это вызовет ошибку
|
|||||||
float b;
|
float b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Абстрактный класс не можен быть истанциирован, но может иметь наследников
|
// Абстрактный класс не может быть истанциирован, но может иметь наследников
|
||||||
abstract class AC {
|
abstract class AC {
|
||||||
int a;
|
int a;
|
||||||
}
|
}
|
||||||
@ -547,8 +567,8 @@ auto ac = new AC(); // это вызовет ошибку
|
|||||||
|
|
||||||
class Implementation : AC {
|
class Implementation : AC {
|
||||||
float b;
|
float b;
|
||||||
|
|
||||||
// final перед методом нефинального класса означает запрет возможности
|
// final перед методом нефинального класса означает запрет возможности
|
||||||
// переопределения метода
|
// переопределения метода
|
||||||
final void test()
|
final void test()
|
||||||
{
|
{
|
||||||
@ -560,7 +580,7 @@ auto impl = new Implementation(); // ОК
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*** Микшины (mixins) ***/
|
/*** Примеси (mixins) ***/
|
||||||
|
|
||||||
// В D можно вставлять код как строку, если эта строка известна на этапе
|
// В D можно вставлять код как строку, если эта строка известна на этапе
|
||||||
// компиляции. Например:
|
// компиляции. Например:
|
||||||
@ -583,8 +603,8 @@ void main() {
|
|||||||
/*** Шаблоны ***/
|
/*** Шаблоны ***/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Шаблон функции. Эта функция принимает аргументы разеых типов, которые
|
Шаблон функции. Эта функция принимает аргументы разных типов, которые
|
||||||
подсталяются вместо T на этапе компиляции. "T" - это не специальный
|
подставляются вместо T на этапе компиляции. "T" - это не специальный
|
||||||
символ, а просто буква. Вместо "T" может быть любое слово, кроме ключевого.
|
символ, а просто буква. Вместо "T" может быть любое слово, кроме ключевого.
|
||||||
*/
|
*/
|
||||||
void print(T)(T value) {
|
void print(T)(T value) {
|
||||||
@ -633,8 +653,8 @@ class Stack(T)
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
/*
|
/*
|
||||||
восклицательный знак - признак шаблона В данном случае мы создаем
|
восклицательный знак - признак шаблона. В данном случае мы создаем
|
||||||
класс и указывем, что "шаблонное" поле будет иметь тип string
|
класс и указываем, что "шаблонное" поле будет иметь тип string
|
||||||
*/
|
*/
|
||||||
auto stack = new Stack!string;
|
auto stack = new Stack!string;
|
||||||
|
|
||||||
@ -660,9 +680,7 @@ void main() {
|
|||||||
несколько единообразных функций, определяющих, _как_ мы получаем доступ
|
несколько единообразных функций, определяющих, _как_ мы получаем доступ
|
||||||
к элементам контейнера, вместо того, чтобы описывать внутреннее устройство
|
к элементам контейнера, вместо того, чтобы описывать внутреннее устройство
|
||||||
этого контейнера. Сложно? На самом деле не очень.
|
этого контейнера. Сложно? На самом деле не очень.
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Простейший вид диапазона - Input Range. Для того, чтобы превратить любой
|
Простейший вид диапазона - Input Range. Для того, чтобы превратить любой
|
||||||
контейнер в Input Range, достаточно реализовать для него 3 метода:
|
контейнер в Input Range, достаточно реализовать для него 3 метода:
|
||||||
- empty - проверяет, пуст ли контейнер
|
- empty - проверяет, пуст ли контейнер
|
||||||
@ -706,8 +724,8 @@ struct StudentRange
|
|||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
auto school = School([
|
auto school = School([
|
||||||
Student("Mike", 1),
|
Student("Mike", 1),
|
||||||
Student("John", 2) ,
|
Student("John", 2) ,
|
||||||
Student("Dan", 3)
|
Student("Dan", 3)
|
||||||
]);
|
]);
|
||||||
auto range = StudentRange(school);
|
auto range = StudentRange(school);
|
||||||
@ -730,6 +748,6 @@ void main(){
|
|||||||
```
|
```
|
||||||
## Что дальше?
|
## Что дальше?
|
||||||
|
|
||||||
[Официальный сайт](http://dlang.org/)
|
- [Официальный сайт](http://dlang.org/)
|
||||||
[Онлайн-книга](http://ddili.org/ders/d.en/)
|
- [Онлайн-книга](http://ddili.org/ders/d.en/)
|
||||||
[Официальная вики](http://wiki.dlang.org/)
|
- [Официальная вики](http://wiki.dlang.org/)
|
||||||
|
Loading…
Reference in New Issue
Block a user