Update d-ru.html.markdown

This commit is contained in:
Anton Pastukhoff 2015-12-12 14:43:56 +05:00
parent b9cde57bc7
commit f854fe1111

View File

@ -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/)