summaryrefslogtreecommitdiffhomepage
path: root/ru-ru
diff options
context:
space:
mode:
Diffstat (limited to 'ru-ru')
-rw-r--r--ru-ru/c++-ru.html.markdown7
-rw-r--r--ru-ru/clojure-ru.html.markdown52
-rw-r--r--ru-ru/common-lisp-ru.html.markdown704
-rw-r--r--ru-ru/crystal-ru.html.markdown584
-rw-r--r--ru-ru/jquery-ru.html.markdown127
-rw-r--r--ru-ru/markdown-ru.html.markdown1
-rw-r--r--ru-ru/php-composer-ru.html.markdown196
-rw-r--r--ru-ru/rust-ru.html.markdown316
8 files changed, 1957 insertions, 30 deletions
diff --git a/ru-ru/c++-ru.html.markdown b/ru-ru/c++-ru.html.markdown
index b9704fc3..35994749 100644
--- a/ru-ru/c++-ru.html.markdown
+++ b/ru-ru/c++-ru.html.markdown
@@ -886,7 +886,6 @@ v.swap(vector<Foo>());
```
## Дальнейшее чтение:
-Наиболее полное и обновленное руководство по С++ можно найти на
-<http://cppreference.com/w/cpp>
-
-Дополнительные ресурсы могут быть найдены на <http://cplusplus.com>
+* Наиболее полное и обновленное руководство по С++ можно найти на [CPP Reference](http://cppreference.com/w/cpp).
+* Дополнительные ресурсы могут быть найдены на [CPlusPlus](http://cplusplus.com).
+* Учебник, посвященный основам языка и настройке среды кодирования, доступен в [TheChernoProject - C ++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb).
diff --git a/ru-ru/clojure-ru.html.markdown b/ru-ru/clojure-ru.html.markdown
index 356d1cc0..19233d23 100644
--- a/ru-ru/clojure-ru.html.markdown
+++ b/ru-ru/clojure-ru.html.markdown
@@ -8,9 +8,9 @@ translators:
lang: ru-ru
---
-Clojure, это представитель семейства Lisp-подобных языков, разработанный
+Clojure — это представитель семейства Lisp-подобных языков, разработанный
для Java Virtual Machine. Язык идейно гораздо ближе к чистому
-[функциональному программированию](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%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) чем его прародитель Common Lisp, но в то же время обладает набором инструментов для работы с состоянием,
+[функциональному программированию](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%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), чем его прародитель Common Lisp, но в то же время обладает набором инструментов для работы с состоянием,
таких как [STM](https://ru.wikipedia.org/wiki/Software_transactional_memory).
Благодаря такому сочетанию технологий в одном языке, разработка программ,
@@ -23,9 +23,9 @@ Clojure, это представитель семейства Lisp-подобн
```clojure
; Комментарии начинаются символом ";".
-; Код на языке Clojure записывается в виде "форм",
+; Код на языке Clojure записывается в виде «форм»,
; которые представляют собой обычные списки элементов, разделенных пробелами,
-; заключённые в круглые скобки
+; заключённые в круглые скобки.
;
; Clojure Reader (инструмент языка, отвечающий за чтение исходного кода),
; анализируя форму, предполагает, что первым элементом формы (т.е. списка)
@@ -76,32 +76,32 @@ Clojure, это представитель семейства Lisp-подобн
'(+ 1 2) ; => (+ 1 2)
; ("'", это краткая запись формы (quote (+ 1 2))
-; "Квотированный" список можно вычислить, передав его функции eval
+; «Квотированный» список можно вычислить, передав его функции eval
(eval '(+ 1 2)) ; => 3
; Коллекции и Последовательности
;;;;;;;;;;;;;;;;;;;
-; Списки (Lists) в clojure структурно представляют собой "связанные списки",
+; Списки (Lists) в clojure структурно представляют собой «связанные списки»,
; тогда как Векторы (Vectors), устроены как массивы.
; Векторы и Списки тоже являются классами Java!
(class [1 2 3]); => clojure.lang.PersistentVector
(class '(1 2 3)); => clojure.lang.PersistentList
-; Список может быть записан, как (1 2 3), но в этом случае
+; Список может быть записан как (1 2 3), но в этом случае
; он будет воспринят reader`ом, как вызов функции.
; Есть два способа этого избежать:
; '(1 2 3) - квотирование,
; (list 1 2 3) - явное конструирование списка с помощью функции list.
-; "Коллекции", это некие наборы данных
+; «Коллекции» — это некие наборы данных.
; И списки, и векторы являются коллекциями:
(coll? '(1 2 3)) ; => true
(coll? [1 2 3]) ; => true
-; "Последовательности" (seqs), это абстракция над наборами данных,
+; «Последовательности» (seqs) — это абстракция над наборами данных,
; элементы которых "упакованы" последовательно.
-; Списки - последовательности, а вектора - нет.
+; Списки — последовательности, а векторы — нет.
(seq? '(1 2 3)) ; => true
(seq? [1 2 3]) ; => false
@@ -119,7 +119,7 @@ Clojure, это представитель семейства Lisp-подобн
; Функция conj добавляет элемент в коллекцию
; максимально эффективным для неё способом.
-; Для списков эффективно добавление в начло, а для векторов - в конец.
+; Для списков эффективно добавление в начло, а для векторов — в конец.
(conj [1 2 3] 4) ; => [1 2 3 4]
(conj '(1 2 3) 4) ; => (4 1 2 3)
@@ -130,7 +130,7 @@ Clojure, это представитель семейства Lisp-подобн
(map inc [1 2 3]) ; => (2 3 4)
(filter even? [1 2 3]) ; => (2)
-; reduce поможет "свернуть" коллекцию
+; reduce поможет «свернуть» коллекцию
(reduce + [1 2 3 4])
; = (+ (+ (+ 1 2) 3) 4)
; => 10
@@ -144,12 +144,12 @@ Clojure, это представитель семейства Lisp-подобн
;;;;;;;;;;;;;;;;;;;;;
; Функция создается специальной формой fn.
-; "Тело" функции может состоять из нескольких форм,
+; «Тело» функции может состоять из нескольких форм,
; но результатом вызова функции всегда будет результат вычисления
; последней из них.
(fn [] "Hello World") ; => fn
-; (Вызов функции требует "оборачивания" fn-формы в форму вызова)
+; (Вызов функции требует «оборачивания» fn-формы в форму вызова)
((fn [] "Hello World")) ; => "Hello World"
; Назначить значению имя можно специальной формой def
@@ -160,7 +160,7 @@ x ; => 1
(def hello-world (fn [] "Hello World"))
(hello-world) ; => "Hello World"
-; Поскольку именование функций - очень частая операция,
+; Поскольку именование функций — очень частая операция,
; clojure позволяет, сделать это проще:
(defn hello-world [] "Hello World")
@@ -211,7 +211,7 @@ x ; => 1
; Отображения могут использовать в качестве ключей любые хэшируемые значения,
; однако предпочтительными являются ключи,
-; являющиеся "ключевыми словами" (keywords)
+; являющиеся «ключевыми словами» (keywords)
(class :a) ; => clojure.lang.Keyword
(def stringmap {"a" 1, "b" 2, "c" 3})
@@ -263,7 +263,7 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
; Исключаются - посредством disj
(disj #{1 2 3} 1) ; => #{2 3}
-; Вызов множества, как функции, позволяет проверить
+; Вызов множества как функции позволяет проверить
; принадлежность элемента этому множеству:
(#{1 2 3} 1) ; => 1
(#{1 2 3} 4) ; => nil
@@ -274,8 +274,8 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
; Полезные формы
;;;;;;;;;;;;;;;;;
-; Конструкции ветвления в clojure, это обычные макросы
-; и подобны их собратьям в других языках:
+; Конструкции ветвления в clojure — это обычные макросы,
+; они подобны своим собратьям в других языках:
(if false "a" "b") ; => "b"
(if false "a") ; => nil
@@ -285,7 +285,7 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
(let [a 1 b 2]
(> a b)) ; => false
-; Несколько форм можно объединить в одну форму посредством do
+; Несколько форм можно объединить в одну форму посредством do.
; Значением do-формы будет значение последней формы из списка вложенных в неё:
(do
(print "Hello")
@@ -298,7 +298,7 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
(str "Hello " name))
(print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff")
-; Ещё один пример - let:
+; Ещё один пример — let:
(let [name "Urkel"]
(print "Saying hello to " name)
(str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel")
@@ -306,7 +306,7 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
; Модули
;;;;;;;;;
-; Форма "use" позволяет добавить в текущее пространство имен
+; Форма use позволяет добавить в текущее пространство имен
; все имена (вместе со значениями) из указанного модуля:
(use 'clojure.set)
@@ -392,7 +392,7 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
my-atom ;=> Atom<#...> (Возвращает объект типа Atom)
@my-atom ; => {:a 1 :b 2}
-; Пример реализации счётчика на атоме
+; Пример реализации счётчика на атоме:
(def counter (atom 0))
(defn inc-counter []
(swap! counter inc))
@@ -414,13 +414,13 @@ my-atom ;=> Atom<#...> (Возвращает объект типа Atom)
Это руководство не претендует на полноту, но мы смеем надеяться, способно вызвать интерес к дальнейшему изучению языка.
-Clojure.org - сайт содержит большое количество статей по языку:
+Сайт Clojure.org содержит большое количество статей по языку:
[http://clojure.org/](http://clojure.org/)
-Clojuredocs.org - сайт документации языка с примерами использования функций:
+Clojuredocs.org — сайт документации языка с примерами использования функций:
[http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core)
-4Clojure - отличный способ закрепить навыки программирования на clojure, решая задачи вместе с коллегами со всего мира:
+4Clojure — отличный способ закрепить навыки программирования на clojure, решая задачи вместе с коллегами со всего мира:
[http://www.4clojure.com/](http://www.4clojure.com/)
Clojure-doc.org (да, именно) неплохой перечень статей для начинающих:
diff --git a/ru-ru/common-lisp-ru.html.markdown b/ru-ru/common-lisp-ru.html.markdown
new file mode 100644
index 00000000..d5f9bf0e
--- /dev/null
+++ b/ru-ru/common-lisp-ru.html.markdown
@@ -0,0 +1,704 @@
+---
+
+language: "Common Lisp"
+filename: commonlisp.lisp
+contributors:
+ - ["Paul Nathan", "https://github.com/pnathan"]
+ - ["Rommel Martinez", "https://ebzzry.io"]
+translators:
+ - ["Michael Filonenko", "https://github.com/filonenko-mikhail"]
+lang: ru-ru
+---
+
+Common Lisp - мультипарадигменный язык программирования общего назначения, подходящий для широкого
+спектра задач.
+Его частенько называют программируемым языком программирования.
+
+Идеальная отправная точка - книга [Common Lisp на практике (перевод)](http://lisper.ru/pcl/).
+Ещё одна популярная книга [Land of Lisp](http://landoflisp.com/).
+И одна из последних книг [Common Lisp Recipes](http://weitz.de/cl-recipes/) вобрала в себя лучшие
+архитектурные решения на основе опыта коммерческой работки автора.
+
+
+
+```common-lisp
+
+;;;-----------------------------------------------------------------------------
+;;; 0. Синтаксис
+;;;-----------------------------------------------------------------------------
+
+;;; Основные формы
+
+;;; Существует два фундамента CL: АТОМ и S-выражение.
+;;; Как правило, сгруппированные S-выражения называют `формами`.
+
+10 ; атом; вычисляется в самого себя
+:thing ; другой атом; вычисляется в символ :thing
+t ; ещё один атом, обозначает `истину` (true)
+(+ 1 2 3 4) ; s-выражение
+'(4 :foo t) ; ещё одно s-выражение
+
+;;; Комментарии
+
+;;; Однострочные комментарии начинаются точкой с запятой. Четыре знака подряд
+;;; используют для комментария всего файла, три для раздела, два для текущего
+;;; определения; один для текущей строки. Например:
+
+;;;; life.lisp
+
+;;; То-сё - пятое-десятое. Оптимизировано для максимального бадабума и ччччч.
+;;; Требуется для функции PoschitatBenzinIsRossiiVBelarus
+
+(defun meaning (life)
+ "Возвращает смысл Жизни"
+ (let ((meh "abc"))
+ ;; Вызывает бадабум
+ (loop :for x :across meh
+ :collect x))) ; сохранить значения в x, и потом вернуть
+
+;;; А вот целый блок комментария можно использовать как угодно.
+;;; Для него используются #| и |#
+
+#| Целый блок комментария, который размазан
+ на несколько строк
+ #|
+ которые могут быть вложенными!
+ |#
+|#
+
+;;; Чем пользоваться
+
+;;; Существует несколько реализаций: и коммерческих, и открытых.
+;;; Все они максимально соответствуют стандарту языка.
+;;; SBCL, например, добротен. А за дополнительными библиотеками
+;;; нужно ходить в Quicklisp
+
+;;; Обычно разработка ведется в текстовом редакторе с запущенным в цикле
+;;; интерпретатором (в CL это Read Eval Print Loop). Этот цикл (REPL)
+;;; позволяет интерактивно выполнять части программы вживую сразу наблюдая
+;;; результат.
+
+;;;-----------------------------------------------------------------------------
+;;; 1. Базовые типы и операторы
+;;;-----------------------------------------------------------------------------
+
+;;; Символы
+
+'foo ; => FOO Символы автоматически приводятся к верхнему регистру.
+
+;;; INTERN создаёт символ из строки.
+
+(intern "AAAA") ; => AAAA
+(intern "aaa") ; => |aaa|
+
+;;; Числа
+
+9999999999999999999999 ; целые
+#b111 ; двоичные => 7
+#o111 ; восьмеричные => 73
+#x111 ; шестнадцатиричные => 273
+3.14159s0 ; с плавающей точкой
+3.14159d0 ; с плавающей точкой с двойной точностью
+1/2 ; рациональные)
+#C(1 2) ; комплексные
+
+;;; Вызов функции пишется как s-выражение (f x y z ....), где f это функция,
+;;; x, y, z, ... аругменты.
+
+(+ 1 2) ; => 3
+
+;;; Если вы хотите просто представить код как данные, воспользуйтесь формой QUOTE
+;;; Она не вычисляет аргументы, а возвращает их как есть.
+;;; Она даёт начало метапрограммированию
+
+(quote (+ 1 2)) ; => (+ 1 2)
+(quote a) ; => A
+
+;;; QUOTE можно сокращенно записать знаком '
+
+'(+ 1 2) ; => (+ 1 2)
+'a ; => A
+
+;;; Арифметические операции
+
+(+ 1 1) ; => 2
+(- 8 1) ; => 7
+(* 10 2) ; => 20
+(expt 2 3) ; => 8
+(mod 5 2) ; => 1
+(/ 35 5) ; => 7
+(/ 1 3) ; => 1/3
+(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
+
+;;; Булевые
+
+t ; истина; любое не-NIL значение `истинно`
+nil ; ложь; а ещё пустой список () тоже `ложь`
+(not nil) ; => T
+(and 0 t) ; => T
+(or 0 nil) ; => 0
+
+;;; Строковые символы
+
+#\A ; => #\A
+#\λ ; => #\GREEK_SMALL_LETTER_LAMDA
+#\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA
+
+;;; Строки это фиксированные массивы символов
+
+"Hello, world!"
+"Тимур \"Каштан\" Бадтрудинов" ; экранировать двойную кавычку обратным слешом
+
+;;; Строки можно соединять
+
+(concatenate 'string "ПРивет, " "мир!") ; => "ПРивет, мир!"
+
+;;; Можно пройтись по строке как по массиву символов
+
+(elt "Apple" 0) ; => #\A
+
+;;; Для форматированного вывода используется FORMAT. Он умеет выводить, как просто значения,
+;;; так и производить циклы и учитывать условия. Первый агрумент указывает куда отправить
+;;; результат. Если NIL, FORMAT вернет результат как строку, если T результат отправиться
+;;; консоль вывода а форма вернет NIL.
+
+(format nil "~A, ~A!" "Привет" "мир") ; => "Привет, мир!"
+(format t "~A, ~A!" "Привет" "мир") ; => NIL
+
+
+;;;-----------------------------------------------------------------------------
+;;; 2. Переменные
+;;;-----------------------------------------------------------------------------
+
+;;; С помощью DEFVAR и DEFPARAMETER вы можете создать глобальную (динамческой видимости)
+;;; переменную.
+;;; Имя переменной может состоять из любых символов кроме: ()",'`;#|\
+
+;;; Разница между DEFVAR и DEFPARAMETER в том, что повторное выполнение DEFVAR
+;;; переменную не поменяет. А вот DEFPARAMETER меняет переменную при каждом вызове.
+
+;;; Обычно глобальные (динамически видимые) переменные содержат звездочки в имени.
+
+(defparameter *some-var* 5)
+*some-var* ; => 5
+
+;;; Можете использовать unicode.
+(defparameter *КУКУ* nil)
+
+;;; Доступ к необъявленной переменной - это непредсказуемое поведение. Не делайте так.
+
+;;; С помощью LET можете сделать локальное связывание.
+;;; В следующем куске кода, `я` связывается с "танцую с тобой" только
+;;; внутри формы (let ...). LET всегда возвращает значение последней формы.
+
+(let ((я "танцую с тобой")) я) ; => "танцую с тобой"
+
+
+;;;-----------------------------------------------------------------------------;
+;;; 3. Структуры и коллекции
+;;;-----------------------------------------------------------------------------;
+
+
+;;; Структуры
+
+(defstruct dog name breed age)
+(defparameter *rover*
+ (make-dog :name "rover"
+ :breed "collie"
+ :age 5))
+*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
+(dog-p *rover*) ; => T
+(dog-name *rover*) ; => "rover"
+
+;;; DEFSTRUCT автоматически создала DOG-P, MAKE-DOG, и DOG-NAME
+
+
+;;; Пары (cons-ячейки)
+
+;;; CONS создаёт пары. CAR и CDR возвращают начало и конец CONS-пары.
+
+(cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB)
+(car (cons 'SUBJECT 'VERB)) ; => SUBJECT
+(cdr (cons 'SUBJECT 'VERB)) ; => VERB
+
+
+;;; Списки
+
+;;; Списки это связанные CONS-пары, в конце самой последней из которых стоит NIL
+;;; (или '() ).
+
+(cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3)
+
+;;; Списки с произвольным количеством элементов удобно создавать с помощью LIST
+
+(list 1 2 3) ; => '(1 2 3)
+
+;;; Если первый аргумент для CONS это атом и второй аргумент список, CONS
+;;; возвращает новую CONS-пару, которая представляет собой список
+
+(cons 4 '(1 2 3)) ; => '(4 1 2 3)
+
+;;; Чтобы объединить списки, используйте APPEND
+
+(append '(1 2) '(3 4)) ; => '(1 2 3 4)
+
+;;; Или CONCATENATE
+
+(concatenate 'list '(1 2) '(3 4)) ; => '(1 2 3 4)
+
+;;; Списки это самый используемый элемент языка. Поэтому с ними можно делать
+;;; многие вещи. Вот несколько примеров:
+
+(mapcar #'1+ '(1 2 3)) ; => '(2 3 4)
+(mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33)
+(remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4)
+(every #'evenp '(1 2 3 4)) ; => NIL
+(some #'oddp '(1 2 3 4)) ; => T
+(butlast '(subject verb object)) ; => (SUBJECT VERB)
+
+
+;;; Вектора
+
+;;; Вектора заданные прямо в коде - это массивы с фиксированной длинной.
+
+#(1 2 3) ; => #(1 2 3)
+
+;;; Для соединения векторов используйте CONCATENATE
+
+(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
+
+
+;;; Массивы
+
+;;; И вектора и строки это подмножества массивов.
+
+;;; Двухмерные массивы
+
+(make-array (list 2 2)) ; => #2A((0 0) (0 0))
+(make-array '(2 2)) ; => #2A((0 0) (0 0))
+(make-array (list 2 2 2)) ; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
+
+;;; Внимание: значение по-умолчанию элемента массива зависит от реализации.
+;;; Лучше явно указывайте:
+
+(make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET)
+
+;;; Для доступа к элементу в позиции 1, 1, 1:
+
+(aref (make-array (list 2 2 2)) 1 1 1) ; => 0
+
+
+;;; Вектора с изменяемой длиной
+
+;;; Вектора с изменяемой длиной при выводе на консоль выглядят также,
+;;; как и вектора, с константной длиной
+
+(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
+ :adjustable t :fill-pointer t))
+*adjvec* ; => #(1 2 3)
+
+;;; Добавление новых элементов
+
+(vector-push-extend 4 *adjvec*) ; => 3
+*adjvec* ; => #(1 2 3 4)
+
+
+;;; Множества, это просто списки:
+
+(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
+(intersection '(1 2 3 4) '(4 5 6 7)) ; => 4
+(union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7)
+(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
+
+;;; Несмотря на все, для действительно больших объемов данных, вам нужно что-то
+;;; лучше, чем просто связанные списки
+
+;;; Словари представлены хеш таблицами.
+
+;;; Создание хеш таблицы:
+
+(defparameter *m* (make-hash-table))
+
+;;; Установка пары ключ-значение
+
+(setf (gethash 'a *m*) 1)
+
+;;; Возврат значения по ключу
+
+(gethash 'a *m*) ; => 1, T
+
+;;; CL выражения умеют возвращать сразу несколько значений.
+
+(values 1 2) ; => 1, 2
+
+;;; которые могут быть распределены по переменным с помощью MULTIPLE-VALUE-BIND
+
+(multiple-value-bind (x y)
+ (values 1 2)
+ (list y x))
+
+; => '(2 1)
+
+;;; GETHASH как раз та функция, которая возвращает несколько значений. Первое
+;;; значение - это значение по ключу в хеш таблицу. Если ключ не был найден,
+;;; возвращает NIL.
+
+;;; Второе возвращаемое значение, указывает был ли ключ в хеш таблице. Если ключа
+;;; не было, то возвращает NIL. Таким образом можно проверить, это значение
+;;; NIL, или ключа просто не было.
+
+;;; Вот возврат значений, в случае когда ключа в хеш таблице не было:
+
+(gethash 'd *m*) ;=> NIL, NIL
+
+;;; Можете задать значение по умолчанию.
+
+(gethash 'd *m* :not-found) ; => :NOT-FOUND
+
+;;; Давайте обработаем возврат несколько значений.
+
+(multiple-value-bind (a b)
+ (gethash 'd *m*)
+ (list a b))
+; => (NIL NIL)
+
+(multiple-value-bind (a b)
+ (gethash 'a *m*)
+ (list a b))
+; => (1 T)
+
+
+;;;-----------------------------------------------------------------------------
+;;; 3. Функции
+;;;-----------------------------------------------------------------------------
+
+;;; Для создания анонимных функций используйте LAMBDA. Функций всегда возвращают
+;;; значение последнего своего выражения. Как выглядит функция при выводе в консоль
+;;; зависит от реализации.
+
+(lambda () "Привет Мир") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>
+
+;;; Для вызова анонимной функции пользуйтесь FUNCALL
+
+(funcall (lambda () "Привет Мир")) ; => "Привет мир"
+(funcall #'+ 1 2 3) ; => 6
+
+;;; FUNCALL сработает и тогда, когда анонимная функция стоит в начале
+;;; неэкранированного списка
+
+((lambda () "Привет Мир")) ; => "Привет Мир"
+((lambda (val) val) "Привет Мир") ; => "Привет Мир"
+
+;;; FUNCALL используется, когда аргументы заранее известны.
+;;; В противном случае используйте APPLY
+
+(apply #'+ '(1 2 3)) ; => 6
+(apply (lambda () "Привет Мир") nil) ; => "Привет Мир"
+
+;;; Для обычной функции с именем используйте DEFUN
+
+(defun hello-world () "Привет Мир")
+(hello-world) ; => "Привет Мир"
+
+;;; Выше видно пустой список (), это место для определения аргументов
+
+(defun hello (name) (format nil "Hello, ~A" name))
+(hello "Григорий") ; => "Привет, Григорий"
+
+;;; Можно указать необязательные аргументы. По умолчанию они будут NIL
+
+(defun hello (name &optional from)
+ (if from
+ (format t "Приветствие для ~A от ~A" name from)
+ (format t "Привет, ~A" name)))
+
+(hello "Георгия" "Василия") ; => Приветствие для Георгия от Василия
+
+;;; Можно явно задать значения по умолчанию
+
+(defun hello (name &optional (from "Мира"))
+ (format nil "Приветствие для ~A от ~A" name from))
+
+(hello "Жоры") ; => Приветствие для Жоры от Мира
+(hello "Жоры" "альпаки") ; => Приветствие для Жоры от альпаки
+
+;;; Можно также задать именованные параметры
+
+(defun generalized-greeter (name &key (from "Мира") (honorific "Господин"))
+ (format t "Здравствуйте, ~A ~A, от ~A" honorific name from))
+
+(generalized-greeter "Григорий")
+; => Здравствуйте, Господин Григорий, от Мира
+
+(generalized-greeter "Григорий" :from "альпаки" :honorific "гражданин")
+; => Здравствуйте, Гражданин Григорий, от альпаки
+
+
+;;;-----------------------------------------------------------------------------
+;;; 4. Равенство или эквивалентность
+;;;-----------------------------------------------------------------------------
+
+;;; У CL сложная система эквивалентности. Взглянем одним глазом.
+
+;;; Для чисел используйте `='
+(= 3 3.0) ; => T
+(= 2 1) ; => NIL
+
+;;; Для идентичености объектов используйте EQL
+(eql 3 3) ; => T
+(eql 3 3.0) ; => NIL
+(eql (list 3) (list 3)) ; => NIL
+
+;;; Для списков, строк, и битовых векторов - EQUAL
+(equal (list 'a 'b) (list 'a 'b)) ; => T
+(equal (list 'a 'b) (list 'b 'a)) ; => NIL
+
+
+;;;-----------------------------------------------------------------------------
+;;; 5. Циклы и ветвления
+;;;-----------------------------------------------------------------------------
+
+;;; Ветвления
+
+(if t ; проверямое значение
+ "случилась истина" ; если, оно было истинно
+ "случилась ложь") ; иначе, когда оно было ложно
+; => "случилась истина"
+
+;;; В форме ветвления if, все не-NIL значения это `истина`
+
+(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO)
+(if (member 'Groucho '(Harpo Groucho Zeppo))
+ 'yep
+ 'nope)
+; => 'YEP
+
+;;; COND это цепочка проверок для нахождения искомого
+(cond ((> 2 2) (error "мимо!"))
+ ((< 2 2) (error "опять мимо!"))
+ (t 'ok)) ; => 'OK
+
+;;; TYPECASE выбирает ветку исходя из типа выражения
+(typecase 1
+ (string :string)
+ (integer :int))
+; => :int
+
+
+;;; Циклы
+
+;;; С рекурсией
+
+(defun fact (n)
+ (if (< n 2)
+ 1
+ (* n (fact(- n 1)))))
+
+(fact 5) ; => 120
+
+;;; И без
+
+(defun fact (n)
+ (loop :for result = 1 :then (* result i)
+ :for i :from 2 :to n
+ :finally (return result)))
+
+(fact 5) ; => 120
+
+(loop :for x :across "abc" :collect x)
+; => (#\a #\b #\c #\d)
+
+(dolist (i '(1 2 3 4))
+ (format t "~A" i))
+; => 1234
+
+
+;;;-----------------------------------------------------------------------------
+;;; 6. Установка значений в переменные (и не только)
+;;;-----------------------------------------------------------------------------
+
+;;; Для присвоения переменной нового значения используйте SETF. Это уже было
+;;; при работе с хеш таблицами.
+
+(let ((variable 10))
+ (setf variable 2))
+; => 2
+
+;;; Для функционального подхода в программировании, старайтесь избегать измений
+;;; в переменных.
+
+;;;-----------------------------------------------------------------------------
+;;; 7. Классы и объекты
+;;;-----------------------------------------------------------------------------
+
+;;; Никаких больше животных в примерах. Берем устройства приводимые в движение
+;;; мускульной силой человека.
+
+(defclass human-powered-conveyance ()
+ ((velocity
+ :accessor velocity
+ :initarg :velocity)
+ (average-efficiency
+ :accessor average-efficiency
+ :initarg :average-efficiency))
+ (:documentation "Устройство движимое человеческой силой"))
+
+;;; Аргументы DEFCLASS:
+;;; 1. Имя класса
+;;; 2. Список родительских классов
+;;; 3. Список полей
+;;; 4. Необязательная метаинформация
+
+;;; Если родительские классы не заданы, используется "стандартный" класс
+;;; Это можно *изменить*, но хорошенько подумайте прежде. Если все-таки
+;;; решились вам поможет "Art of the Metaobject Protocol"
+
+(defclass bicycle (human-powered-conveyance)
+ ((wheel-size
+ :accessor wheel-size
+ :initarg :wheel-size
+ :documentation "Diameter of the wheel.")
+ (height
+ :accessor height
+ :initarg :height)))
+
+(defclass recumbent (bicycle)
+ ((chain-type
+ :accessor chain-type
+ :initarg :chain-type)))
+
+(defclass unicycle (human-powered-conveyance) nil)
+
+(defclass canoe (human-powered-conveyance)
+ ((number-of-rowers
+ :accessor number-of-rowers
+ :initarg :number-of-rowers)))
+
+;;; Если вызвать DESCRIBE для HUMAN-POWERED-CONVEYANCE то получите следующее:
+
+(describe 'human-powered-conveyance)
+
+; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE
+; [symbol]
+;
+; HUMAN-POWERED-CONVEYANCE names the standard-class #<STANDARD-CLASS
+; HUMAN-POWERED-CONVEYANCE>:
+; Documentation:
+; A human powered conveyance
+; Direct superclasses: STANDARD-OBJECT
+; Direct subclasses: UNICYCLE, BICYCLE, CANOE
+; Not yet finalized.
+; Direct slots:
+; VELOCITY
+; Readers: VELOCITY
+; Writers: (SETF VELOCITY)
+; AVERAGE-EFFICIENCY
+; Readers: AVERAGE-EFFICIENCY
+; Writers: (SETF AVERAGE-EFFICIENCY)
+
+;;; CL задизайнен как интерактивная система. В рантайме доступна информация о
+;;; типе объектов.
+
+;;; Давайте посчитаем расстояние, которое пройдет велосипед за один оборот колеса
+;;; по формуле C = d * pi
+
+(defmethod circumference ((object bicycle))
+ (* pi (wheel-size object)))
+
+;;; PI - это константа в CL
+
+;;; Предположим мы нашли, что критерий эффективности логарифмически связан
+;;; с гребцами каноэ. Тогда вычисление можем сделать сразу при инициализации.
+
+;;; Инициализируем объект после его создания:
+
+(defmethod initialize-instance :after ((object canoe) &rest args)
+ (setf (average-efficiency object) (log (1+ (number-of-rowers object)))))
+
+
+;;; Давайте проверим что получилось с этой самой эффективностью...
+
+(average-efficiency (make-instance 'canoe :number-of-rowers 15))
+; => 2.7725887
+
+
+;;;-----------------------------------------------------------------------------
+;;; 8. Макросы
+;;;-----------------------------------------------------------------------------
+
+;;; Макросы позволяют расширить синаксис языка. В CL нет например цикла WHILE,
+;;; но его проще простого реализовать на макросах. Если мы отбросим наши
+;;; ассемблерные (или алгольные) инстинкты, мы взлетим на крыльях:
+
+(defmacro while (condition &body body)
+ "Пока `условие` истинно, выполняется `тело`.
+`Условие` проверяется перед каждым выполнением `тела`"
+ (let ((block-name (gensym)) (done (gensym)))
+ `(tagbody
+ ,block-name
+ (unless ,condition
+ (go ,done))
+ (progn
+ ,@body)
+ (go ,block-name)
+ ,done)))
+
+;;; Взглянем на более высокоуровневую версию этого макроса:
+
+(defmacro while (condition &body body)
+ "Пока `условие` истинно, выполняется `тело`.
+`Условие` проверяется перед каждым выполнением `тела`"
+ `(loop while ,condition
+ do
+ (progn
+ ,@body)))
+
+;;; В современных комиляторах LOOP так же эффективен как и приведенный
+;;; выше код. Поэтому используйте его, его проще читать.
+
+;;; В макросах используются символы ```, `,` и `@`. ``` - это оператор
+;;; квазиквотирования - это значит что форма исполнятся не будет, а вернется
+;;; как данные. Оператаор `,` позволяет исполнить форму внутри
+;;; квазиквотирования. Оператор `@` исполняет форму внутри квазиквотирования
+;;; но полученный список вклеивает по месту.
+
+;;; GENSYM создаёт уникальный символ, который гарантировано больше нигде в
+;;; системе не используется. Так надо потому, что макросы разворачиваются
+;;; во время компиляции и переменные объявленные в макросе могут совпасть
+;;; по имени с переменными в обычном коде.
+
+;;; Дальнйешую информацию о макросах ищите в книгах Practical Common Lisp
+;;; и On Lisp
+```
+
+## Для чтения
+
+На русском
+- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
+
+На английском
+- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
+- [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)
+
+
+## Дополнительная информация
+
+На русском
+
+- [Lisper.ru](http://lisper.ru/)
+
+На английском
+
+- [CLiki](http://www.cliki.net/)
+- [common-lisp.net](https://common-lisp.net/)
+- [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
+- [Lisp Lang](http://lisp-lang.org/)
+
+
+## Благодарности в английской версии
+
+Спасибо людям из Scheme за отличную статью, взятую за основу для
+Common Lisp.
+
+
+- [Paul Khuong](https://github.com/pkhuong) за хорошую вычитку.
diff --git a/ru-ru/crystal-ru.html.markdown b/ru-ru/crystal-ru.html.markdown
new file mode 100644
index 00000000..87d12f23
--- /dev/null
+++ b/ru-ru/crystal-ru.html.markdown
@@ -0,0 +1,584 @@
+---
+language: crystal
+filename: learncrystal-ru.cr
+contributors:
+ - ["Vitalii Elenhaupt", "http://veelenga.com"]
+ - ["Arnaud Fernandés", "https://github.com/TechMagister/"]
+translators:
+ - ["Den Patin", "https://github.com/denpatin"]
+lang: ru-ru
+---
+
+```crystal
+# — так начинается комментарий
+
+
+# Всё является объектом
+nil.class #=> Nil
+100.class #=> Int32
+true.class #=> Bool
+
+# Возвращают false только nil, false и пустые указатели
+!nil #=> true : Bool
+!false #=> true : Bool
+!0 #=> false : Bool
+
+
+# Целые числа
+
+1.class #=> Int32
+
+# Четыре типа целых чисел со знаком
+1_i8.class #=> Int8
+1_i16.class #=> Int16
+1_i32.class #=> Int32
+1_i64.class #=> Int64
+
+# Четыре типа целых чисел без знака
+1_u8.class #=> UInt8
+1_u16.class #=> UInt16
+1_u32.class #=> UInt32
+1_u64.class #=> UInt64
+
+2147483648.class #=> Int64
+9223372036854775808.class #=> UInt64
+
+# Двоичные числа
+0b1101 #=> 13 : Int32
+
+# Восьмеричные числа
+0o123 #=> 83 : Int32
+
+# Шестнадцатеричные числа
+0xFE012D #=> 16646445 : Int32
+0xfe012d #=> 16646445 : Int32
+
+# Числа с плавающей точкой
+
+1.0.class #=> Float64
+
+# Два типа чисел с плавающей запятой
+1.0_f32.class #=> Float32
+1_f32.class #=> Float32
+
+1e10.class #=> Float64
+1.5e10.class #=> Float64
+1.5e-7.class #=> Float64
+
+
+# Символьные литералы
+
+'a'.class #=> Char
+
+# Восьмеричный код символа
+'\101' #=> 'A' : Char
+
+# Код символа Unicode
+'\u0041' #=> 'A' : Char
+
+
+# Строки
+
+"s".class #=> String
+
+# Строки неизменяемы
+s = "hello, " #=> "hello, " : String
+s.object_id #=> 134667712 : UInt64
+s += "Crystal" #=> "hello, Crystal" : String
+s.object_id #=> 142528472 : UInt64
+
+# Поддерживается интерполяция строк
+"sum = #{1 + 2}" #=> "sum = 3" : String
+
+# Поддерживается многострочность
+"This is
+ multiline string"
+
+# Строка с двойными кавычками
+%(hello "world") #=> "hello \"world\""
+
+
+# Символы — константы без значения, определяемые только именем. Часто
+# используются вместо часто используемых строк для лучшей производительности.
+# На внутреннем уровне они представлены как Int32.
+
+:symbol.class #=> Symbol
+
+sentence = :question? # :"question?" : Symbol
+
+sentence == :question? #=> true : Bool
+sentence == :exclamation! #=> false : Bool
+sentence == "question?" #=> false : Bool
+
+
+# Массивы
+
+[1, 2, 3].class #=> Array(Int32)
+[1, "hello", 'x'].class #=> Array(Int32 | String | Char)
+
+# При объявлении пустого массива необходимо указать тип его элементов
+[] # Syntax error: for empty arrays use '[] of ElementType'
+[] of Int32 #=> [] : Array(Int32)
+Array(Int32).new #=> [] : Array(Int32)
+
+# Элементы внутри массива имеют свои индексы
+array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] : Array(Int32)
+array[0] #=> 1 : Int32
+array[10] # raises IndexError
+array[-6] # raises IndexError
+array[10]? #=> nil : (Int32 | Nil)
+array[-6]? #=> nil : (Int32 | Nil)
+
+# Можно получать элементы по индексу с конца
+array[-1] #=> 5
+
+# С начала и с указанием размера итогового массива
+array[2, 3] #=> [3, 4, 5]
+
+# Или посредством указания диапазона
+array[1..3] #=> [2, 3, 4]
+
+# Добавление в массив
+array << 6 #=> [1, 2, 3, 4, 5, 6]
+
+# Удаление элемента из конца массива
+array.pop #=> 6
+array #=> [1, 2, 3, 4, 5]
+
+# Удаление элемента из начала массива
+array.shift #=> 1
+array #=> [2, 3, 4, 5]
+
+# Проверка на наличие элемента в массиве
+array.includes? 3 #=> true
+
+# Синтаксический сахар для массива строк и символов
+%w(one two three) #=> ["one", "two", "three"] : Array(String)
+%i(one two three) #=> [:one, :two, :three] : Array(Symbol)
+
+# Массивоподобный синтаксис используется и для других типов, только если для
+# них определены методы .new и #<<
+set = Set{1, 2, 3} #=> [1, 2, 3]
+set.class #=> Set(Int32)
+
+# Вышеприведенное эквивалентно следующему
+set = Set(typeof(1, 2, 3)).new
+set << 1
+set << 2
+set << 3
+
+
+# Хэши
+
+{1 => 2, 3 => 4}.class #=> Hash(Int32, Int32)
+{1 => 2, 'a' => 3}.class #=> Hash(Int32 | Char, Int32)
+
+# При объявлении пустого хэша необходимо указать типы ключа и значения
+{} # Syntax error
+{} of Int32 => Int32 # {}
+Hash(Int32, Int32).new # {}
+
+# Значения в хэше легко найти по ключу
+hash = {"color" => "green", "number" => 5}
+hash["color"] #=> "green"
+hash["no_such_key"] #=> Missing hash key: "no_such_key" (KeyError)
+hash["no_such_key"]? #=> nil
+
+# Проверка наличия ключа в хэше
+hash.has_key? "color" #=> true
+
+# Синтаксический сахар для символьных и строковых ключей
+{key1: 'a', key2: 'b'} # {:key1 => 'a', :key2 => 'b'}
+{"key1": 'a', "key2": 'b'} # {"key1" => 'a', "key2" => 'b'}
+
+# Хэшеподобный синтаксис используется и для других типов, только если для них
+# определены методы .new и #[]=
+class MyType
+ def []=(key, value)
+ puts "do stuff"
+ end
+end
+
+MyType{"foo" => "bar"}
+
+# Вышеприведенное эквивалентно следующему
+tmp = MyType.new
+tmp["foo"] = "bar"
+tmp
+
+
+# Диапазоны
+
+1..10 #=> Range(Int32, Int32)
+Range.new(1, 10).class #=> Range(Int32, Int32)
+
+# Включающий и исключающий диапазоны
+(3..5).to_a #=> [3, 4, 5]
+(3...5).to_a #=> [3, 4]
+
+# Проверка на вхождение в диапазон
+(1..8).includes? 2 #=> true
+
+
+# Кортежи
+# Неизменяемые последовательности фиксированного размера, содержащие,
+# как правило, элементы разных типов
+
+{1, "hello", 'x'}.class #=> Tuple(Int32, String, Char)
+
+# Доступ к элементам осуществляется по индексу
+tuple = {:key1, :key2}
+tuple[1] #=> :key2
+tuple[2] #=> syntax error : Index out of bound
+
+# Элементы кортежей можно попарно присвоить переменным
+a, b, c = {:a, 'b', "c"}
+a #=> :a
+b #=> 'b'
+c #=> "c"
+
+
+# Процедуры
+# Указатели на функцию с необязательным содержимым (замыкание).
+# Обычно создаётся с помощью специального литерала ->
+
+proc = ->(x : Int32) { x.to_s }
+proc.class # Proc(Int32, String)
+# Или посредством метода .new
+Proc(Int32, String).new { |x| x.to_s }
+
+# Вызываются посредством метода .call
+proc.call 10 #=> "10"
+
+
+# Управляющие операторы
+
+if true
+ "if statement"
+elsif false
+ "else-if, optional"
+else
+ "else, also optional"
+end
+
+puts "if as a suffix" if true
+
+# if как часть выражения
+a = if 2 > 1
+ 3
+ else
+ 4
+ end
+
+a #=> 3
+
+# Тернарный if
+a = 1 > 2 ? 3 : 4 #=> 4
+
+# Оператор выбора
+cmd = "move"
+
+action = case cmd
+ when "create"
+ "Creating..."
+ when "copy"
+ "Copying..."
+ when "move"
+ "Moving..."
+ when "delete"
+ "Deleting..."
+end
+
+action #=> "Moving..."
+
+
+# Циклы
+
+index = 0
+while index <= 3
+ puts "Index: #{index}"
+ index += 1
+end
+# Index: 0
+# Index: 1
+# Index: 2
+# Index: 3
+
+index = 0
+until index > 3
+ puts "Index: #{index}"
+ index += 1
+end
+# Index: 0
+# Index: 1
+# Index: 2
+# Index: 3
+
+# Но лучше использовать each
+(1..3).each do |index|
+ puts "Index: #{index}"
+end
+# Index: 1
+# Index: 2
+# Index: 3
+
+# Тип переменной зависит от типа выражения
+if a < 3
+ a = "hello"
+else
+ a = true
+end
+typeof a #=> (Bool | String)
+
+if a && b
+ # здесь гарантируется, что и a, и b — не nil
+end
+
+if a.is_a? String
+ a.class #=> String
+end
+
+
+# Методы
+
+def double(x)
+ x * 2
+end
+
+# Методы (а также любые блоки) всегда возвращают значение последнего выражения
+double(2) #=> 4
+
+# Скобки можно опускать, если вызов метода не вносит двусмысленности
+double 3 #=> 6
+
+double double 3 #=> 12
+
+def sum(x, y)
+ x + y
+end
+
+# Параметры методов перечисляются через запятую
+sum 3, 4 #=> 7
+
+sum sum(3, 4), 5 #=> 12
+
+
+# yield
+
+# У всех методов есть неявный необязательный параметр блока, который можно
+# вызвать ключевым словом yield
+
+def surround
+ puts '{'
+ yield
+ puts '}'
+end
+
+surround { puts "hello world" }
+
+# {
+# hello world
+# }
+
+# Методу можно передать блок
+# & — ссылка на переданный блок
+def guests(&block)
+ block.call "some_argument"
+end
+
+# Методу можно передать список параметров, доступ к ним будет как к массиву
+# Для этого используется оператор *
+def guests(*array)
+ array.each { |guest| puts guest }
+end
+
+# Если метод возвращает массив, можно попарно присвоить значение каждого из его
+# элементов переменным
+def foods
+ ["pancake", "sandwich", "quesadilla"]
+end
+breakfast, lunch, dinner = foods
+breakfast #=> "pancake"
+dinner #=> "quesadilla"
+
+# По соглашению название методов, возвращающих булево значение, должно
+# оканчиваться вопросительным знаком
+5.even? # false
+5.odd? # true
+
+# Если название метода оканчивается восклицательным знаком, по соглашению это
+# означает, что метод делает что-то необратимое, например изменяет получателя.
+# Некоторые методы имеют две версии: "опасную" версию с !, которая что-то
+# меняет, и "безопасную", которая просто возвращает новое значение
+company_name = "Dunder Mifflin"
+company_name.gsub "Dunder", "Donald" #=> "Donald Mifflin"
+company_name #=> "Dunder Mifflin"
+company_name.gsub! "Dunder", "Donald"
+company_name #=> "Donald Mifflin"
+
+
+# Классы
+# Определяются с помощью ключевого слова class
+
+class Human
+
+ # Переменная класса является общей для всех экземпляров этого класса
+ @@species = "H. sapiens"
+
+ # Объявление типа переменной name экземпляра класса
+ @name : String
+
+ # Базовый конструктор
+ # Значением первого параметра инициализируем переменную @name.
+ # То же делаем и со вторым параметром — переменная @age. В случае, если мы
+ # не передаём второй параметр, для инициализации @age будет взято значение
+ # по умолчанию (в данном случае — 0)
+ def initialize(@name, @age = 0)
+ end
+
+ # Базовый метод установки значения переменной
+ def name=(name)
+ @name = name
+ end
+
+ # Базовый метод получения значения переменной
+ def name
+ @name
+ end
+
+ # Синтаксический сахар одновременно для двух методов выше
+ property :name
+
+ # А также по отдельности
+ getter :name
+ setter :name
+
+ # Метод класса определяется ключевым словом self, чтобы его можно было
+ # различить с методом экземпляра класса. Такой метод можно вызвать только
+ # на уровне класса, а не экземпляра.
+ def self.say(msg)
+ puts msg
+ end
+
+ def species
+ @@species
+ end
+end
+
+
+# Создание экземпляра класса
+jim = Human.new("Jim Halpert")
+
+dwight = Human.new("Dwight K. Schrute")
+
+# Вызов методов экземпляра класса
+jim.species #=> "H. sapiens"
+jim.name #=> "Jim Halpert"
+jim.name = "Jim Halpert II" #=> "Jim Halpert II"
+jim.name #=> "Jim Halpert II"
+dwight.species #=> "H. sapiens"
+dwight.name #=> "Dwight K. Schrute"
+
+# Вызов метода класса
+Human.say("Hi") #=> выведет "Hi" и вернёт nil
+
+# Переменные экземпляра класса (@) видно только в пределах экземпляра
+class TestClass
+ @var = "I'm an instance var"
+end
+
+# Переменные класса (@) видны как в экземплярах класса, так и в самом классе
+class TestClass
+ @@var = "I'm a class var"
+end
+
+# Переменные с большой буквы — это константы
+Var = "I'm a constant"
+Var = "can't be updated" # Error: already initialized constant Var
+
+# Примеры
+
+# Базовый класс
+class Human
+ @@foo = 0
+
+ def self.foo
+ @@foo
+ end
+
+ def self.foo=(value)
+ @@foo = value
+ end
+end
+
+# Класс-потомок
+class Worker < Human
+end
+
+Human.foo #=> 0
+Worker.foo #=> 0
+
+Human.foo = 2 #=> 2
+Worker.foo #=> 0
+
+Worker.foo = 3 #=> 3
+Human.foo #=> 2
+Worker.foo #=> 3
+
+module ModuleExample
+ def foo
+ "foo"
+ end
+end
+
+# Подключение модуля в класс добавляет его методы в экземпляр класса
+# Расширение модуля добавляет его методы в сам класс
+
+class Person
+ include ModuleExample
+end
+
+class Book
+ extend ModuleExample
+end
+
+Person.foo # => undefined method 'foo' for Person:Class
+Person.new.foo # => 'foo'
+Book.foo # => 'foo'
+Book.new.foo # => undefined method 'foo' for Book
+
+
+# Обработка исключений
+
+# Создание пользовательского типа исключения
+class MyException < Exception
+end
+
+# Ещё одного
+class MyAnotherException < Exception; end
+
+ex = begin
+ raise MyException.new
+rescue ex1 : IndexError
+ "ex1"
+rescue ex2 : MyException | MyAnotherException
+ "ex2"
+rescue ex3 : Exception
+ "ex3"
+rescue ex4 # без указания конкретного типа исключения будут "отлавливаться" все
+ "ex4"
+end
+
+ex #=> "ex2"
+
+```
+
+## Дополнительная информация
+
+### На русском
+
+- [Официальная документация](http://ru.crystal-lang.org/docs/)
+
+### На английском
+
+- [Official Documentation](http://crystal-lang.org/)
diff --git a/ru-ru/jquery-ru.html.markdown b/ru-ru/jquery-ru.html.markdown
new file mode 100644
index 00000000..471b4e24
--- /dev/null
+++ b/ru-ru/jquery-ru.html.markdown
@@ -0,0 +1,127 @@
+---
+category: tool
+tool: jquery
+contributors:
+ - ["Sawyer Charles", "https://github.com/xssc"]
+translators:
+ - ["Ev Bogdanov", "https://github.com/evbogdanov"]
+lang: ru-ru
+filename: jquery-ru.js
+---
+
+jQuery — это библиотека JavaScript, которая помогает "делать больше, писать меньше". Она выполняет множество типичных JavaScript-задач, упрощая написание кода. jQuery используется крупными компаниями и разработчиками со всего мира. Она упрощает и ускоряет работу с AJAX, с событиями, с DOM и со многим другим.
+
+Поскольку jQuery является библиотекой JavaScript, вам следует начать с [изучения JavaScript](https://learnxinyminutes.com/docs/ru-ru/javascript-ru/).
+
+```js
+
+
+///////////////////////////////////
+// 1. Селекторы
+
+// Для получения элемента в jQuery используются селекторы
+var page = $(window); // Получить страницу целиком
+
+// В качестве селектора может выступать CSS-селектор
+var paragraph = $('p'); // Получить все <p> элементы
+var table1 = $('#table1'); // Получить элемент с идентификатором 'table1'
+var squares = $('.square'); // Получить все элементы с классом 'square'
+var square_p = $('p.square') // Получить <p> элементы с классом 'square'
+
+
+///////////////////////////////////
+// 2. События и эффекты
+// jQuery прекрасно справляется с обработкой событий
+// Часто используемое событие — это событие документа 'ready'
+// Вы можете использовать метод 'ready', который сработает, как только документ полностью загрузится
+$(document).ready(function(){
+ // Код не выполнится до тех пор, пока документ не будет загружен
+});
+// Обработку события можно вынести в отдельную функцию
+function onAction() {
+ // Код выполнится, когда произойдёт событие
+}
+$('#btn').click(onAction); // Обработчик события сработает при клике
+
+// Другие распространённые события:
+$('#btn').dblclick(onAction); // Двойной клик
+$('#btn').hover(onAction); // Наведение курсора
+$('#btn').focus(onAction); // Фокус
+$('#btn').blur(onAction); // Потеря фокуса
+$('#btn').submit(onAction); // Отправка формы
+$('#btn').select(onAction); // Когда выбрали элемент
+$('#btn').keydown(onAction); // Когда нажали клавишу
+$('#btn').keyup(onAction); // Когда отпустили клавишу
+$('#btn').keypress(onAction); // Когда нажали символьную клавишу (нажатие привело к появлению символа)
+$('#btn').mousemove(onAction); // Когда переместили курсор мыши
+$('#btn').mouseenter(onAction); // Когда навели курсор на элемент
+$('#btn').mouseleave(onAction); // Когда сдвинули курсор с элемента
+
+
+// Вы можете не только обрабатывать события, но и вызывать их
+$('#btn').dblclick(); // Вызвать двойной клик на элементе
+
+// Для одного селектора возможно назначить несколько обработчиков событий
+$('#btn').on(
+ {dblclick: myFunction1} // Обработать двойной клик
+ {blur: myFunction1} // Обработать исчезновение фокуса
+);
+
+// Вы можете перемещать и прятать элементы с помощью методов-эффектов
+$('.table').hide(); // Спрятать элемент(ы)
+
+// Обратите внимание: вызов функции в этих методах всё равно спрячет сам элемент
+$('.table').hide(function(){
+ // Сначала спрятать элемент, затем вызвать функцию
+});
+
+// Вы можете хранить селекторы в переменных
+var tables = $('.table');
+
+// Некоторые основные методы для манипуляций с документом:
+tables.hide(); // Спрятать элемент(ы)
+tables.show(); // Показать элемент(ы)
+tables.toggle(); // Спрятать/показать
+tables.fadeOut(); // Плавное исчезновение
+tables.fadeIn(); // Плавное появление
+tables.fadeToggle(); // Плавное исчезновение или появление
+tables.fadeTo(0.5); // Изменение прозрачности
+tables.slideUp(); // Свернуть элемент
+tables.slideDown(); // Развернуть элемент
+tables.slideToggle(); // Свернуть или развернуть
+
+// Все эти методы принимают скорость (в миллисекундах) и функцию обратного вызова
+tables.hide(1000, myFunction); // Анимация длится 1 секунду, затем вызов функции
+
+// В методе 'fadeTo' вторым параметром обязательно идёт прозрачность
+tables.fadeTo(2000, 0.1, myFunction); // Прозрачность меняется в течение 2 секунд до 0.1, затем вызывается функция
+
+// Метод 'animate' позволяет делать более продвинутую анимацию
+tables.animate({"margin-top": "+=50", height: "100px"}, 500, myFunction);
+
+
+///////////////////////////////////
+// 3. Манипуляции
+
+// Манипуляции похожи на эффекты, но позволяют добиться большего
+$('div').addClass('taming-slim-20'); // Добавить класс 'taming-slim-20' ко всем <div> элементам
+
+// Часто встречающиеся методы манипуляций
+$('p').append('Hello world'); // Добавить в конец элемента
+$('p').attr('class'); // Получить атрибут
+$('p').attr('class', 'content'); // Установить атрибут
+$('p').hasClass('taming-slim-20'); // Проверить наличие класса
+$('p').height(); // Получить или установить высоту элемента
+
+
+// Во многих методах вам доступна информация ТОЛЬКО о первом элементе из выбранных
+$('p').height(); // Вы получите высоту только для первого <p> элемента
+
+// Метод 'each' позволяет это исправить и пройтись по всем выбранным вами элементам
+var heights = [];
+$('p').each(function() {
+ heights.push($(this).height()); // Добавить высоту всех <p> элементов в массив
+});
+
+
+```
diff --git a/ru-ru/markdown-ru.html.markdown b/ru-ru/markdown-ru.html.markdown
index 91f53f54..579a9a20 100644
--- a/ru-ru/markdown-ru.html.markdown
+++ b/ru-ru/markdown-ru.html.markdown
@@ -43,6 +43,7 @@ Markdown является надмножеством HTML, поэтому люб
и попадают в итоговый HTML без изменений. Однако следует понимать,
что эта же особенность не позволяет использовать разметку Markdown внутри
HTML-элементов -->
+```
## Заголовки
diff --git a/ru-ru/php-composer-ru.html.markdown b/ru-ru/php-composer-ru.html.markdown
new file mode 100644
index 00000000..ef6e4912
--- /dev/null
+++ b/ru-ru/php-composer-ru.html.markdown
@@ -0,0 +1,196 @@
+---
+category: tool
+tool: composer
+contributors:
+ - ["Alesey Lysenko", "https://github.com/nasgul"]
+filename: LearnComposer-ru.sh
+lang: ru-ru
+---
+
+[Composer](https://getcomposer.org/) это инструмент управления зависимостями в PHP.
+Он позволяет вам декларировать библиотеки, от которых зависит ваш проект,
+и он будет управлять (устанавливать / обновлять) их для вас.
+
+# Установка
+
+```sh
+# Устанавливаем composer.phar в текущую папку
+curl -sS https://getcomposer.org/installer | php
+# Если вы используете этот подход, вам нужно будет вызвать композер следующим образом:
+php composer.phar about
+
+# Устанавливаем с бинарников ~/bin/composer
+# Примечание: убедитесь, что ~/bin находится в переменной PATH вашего окружения
+curl -sS https://getcomposer.org/installer | php -- --install-dir=~/bin --filename=composer
+```
+
+Пользователи Windows должны следовать
+[Инструкциям по установке в Windows ](https://getcomposer.org/doc/00-intro.md#installation-windows)
+
+## Подтверждение установки
+
+```sh
+# # Проверить версию и параметры списка
+composer
+
+# Получить дополнительную помощь для параметров
+composer help require
+
+# Проверьте, способен ли Composer делать то, что ему нужно, и если он обновлен
+композитор диагностирует
+composer diagnose
+composer diag # shorthand
+
+# Обновление Composer к последней версии
+composer self-update
+composer self # shorthand
+```
+
+# Использование
+
+Композитор сохраняет ваши зависимости проекта в `composer.json`.
+Вы можете отредактировать этот файл, но лучше всего позволить Composer управлять им для вас.
+
+```sh
+# Создать новый проект в текущей папке
+composer init
+# запускается интерактивная анкета с просьбой предоставить подробную информацию о вашем проекте.
+# Оставляя их пустым, все прекрасно, если вы не делаете другие проекты зависимыми от этого.
+
+# Если файл composer.json уже существует, загрузите зависимости
+composer install
+
+# Чтобы загрузить только производственные зависимости, т. Е. Исключая зависимости разработки
+composer install --no-dev
+
+# Добавить зависимость от этого проекта
+composer require guzzlehttp/guzzle
+# выяснит, какая последняя версия guzzlehttp / guzzle есть,
+# загрузите ее и добавьте новую зависимость в поле require.console.
+
+composer require guzzlehttp/guzzle:6.0.*
+# будет загружать последнюю версию, соответствующую шаблону (например, 6.0.2),
+# и добавить зависимость к полю require.json
+
+composer require --dev phpunit/phpunit:~4.5.0
+# потребуется как зависимость от разработки.
+# Будет использовать последнюю версию> = 4.5.0 и <4.6.0
+
+composer require-dev phpunit/phpunit:^4.5.0
+# потребуется как зависимость от разработки. Будет использовать последнюю версию> = 4.5.0 и <5.0
+
+# Для получения дополнительной информации о совместимости версий Composer см.
+# [Документация композитора по версиям] (https://getcomposer.org/doc/articles/versions.md)
+# для получения более подробной информации
+
+# Чтобы узнать, какие пакеты доступны для установки и в настоящее время установлены
+composer show
+
+# Чтобы узнать, какие пакеты в настоящее время установлены
+composer show --installed
+
+# Чтобы найти пакет с «mailgun» в его названии или описании
+composer search mailgun
+```
+
+[Packagist.org](https://packagist.org/) является основным хранилищем для пакетов Composer.
+Поиск там для существующих сторонних пакетов.
+
+## `composer.json` vs `composer.lock`
+
+Файл `composer.json` хранит ваши параметры плавающей версии вашего проекта для каждой зависимости,
+а также другую информацию.
+
+
+Файл `composer.lock` хранит точно, какую версию он загрузил для каждой зависимости.
+Никогда не редактируйте этот файл.
+
+Если вы включите файл `composer.lock` в свой репозиторий git,
+каждый разработчик установит текущую версию зависимостей.
+Даже когда выпущена новая версия зависимости, Composer продолжит загрузку версии,
+записанной в файле блокировки.
+
+```sh
+# Если вы хотите обновить все зависимости до их новейшей версии,
+# которые по-прежнему соответствуют вашим предпочтениям в версии обновление композитора
+composer update
+
+# Если вам нужна новая версия определенной зависимости:
+composer update phpunit/phpunit
+
+# Если вы хотите перенести пакет на более новую версию,
+# вам может потребоваться сначала удалить старый пакет и его зависимости.
+composer remove --dev phpunit/phpunit
+composer require --dev phpunit/phpunit:^5.0
+```
+
+## Автозагрузчик
+
+Composer создает класс автозагрузки, который вы можете потребовать от своего приложения.
+Вы можете создавать экземпляры классов через их пространство имен.
+
+```php
+require __DIR__ . '/vendor/autoload.php';
+
+$mailgun = new Mailgun\Mailgun("key");
+```
+
+### PSR-4 Autoloader
+
+### Автозагрузчик PSR-4
+
+Вы можете добавить свои собственные пространства имен в автозагрузчик.
+
+Вы можете добавить свои собственные пространства имен в автозагрузчик.
+
+В `composer.json` добавьте поле 'autoload':
+
+```json
+{
+ "autoload": {
+ "psr-4": {"Acme\\": "src/"}
+ }
+}
+```
+Это скажет автозагрузчику искать что-либо в пространстве имен `\ Acme \` в папке `src`.
+
+Вы также можете использовать
+[PSR-0, Classmap или просто список файлов для включения](https://getcomposer.org/doc/04-schema.md#autoload).
+Также существует поле `autoload-dev` для пространств имен, предназначенных только для разработки.
+
+При добавлении или изменении ключа автозагрузки вам необходимо перестроить автозагрузчик:
+
+```sh
+composer dump-autoload
+composer dump # shorthand
+
+# Оптимизирует пакеты PSR0 и PSR4 для загрузки классов.
+# Медленно запускается, но улучшает производительность при производстве.
+composer dump-autoload --optimize --no-dev
+```
+
+# Composer Кэш
+
+```sh
+# Composer сохранит загруженные пакеты для использования в будущем. Очистите его с помощью:
+composer clear-cache
+```
+
+# Поиск проблемы
+
+```sh
+composer diagnose
+composer self-update
+composer clear-cache
+```
+
+## Темы, которые пока (пока) не включены в этот учебник
+
+* Создание и распространение ваших собственных пакетов на Packagist.org или в другом месте
+* Предварительные и пост-скриптовые перехватчики: запуск задач,
+когда происходят определенные события композитора
+
+### Рекомендации
+
+* [Composer - Dependency Manager for PHP](https://getcomposer.org/)
+* [Packagist.org](https://packagist.org/)
diff --git a/ru-ru/rust-ru.html.markdown b/ru-ru/rust-ru.html.markdown
new file mode 100644
index 00000000..7bd2809a
--- /dev/null
+++ b/ru-ru/rust-ru.html.markdown
@@ -0,0 +1,316 @@
+---
+language: rust
+
+filename: learnrust-ru.rs
+contributors:
+ - ["P1start", "http://p1start.github.io/"]
+translators:
+ - ["Anatolii Kosorukov", "https://github.com/java1cprog"]
+lang: ru-ru
+
+---
+
+Rust сочетает в себе низкоуровневый контроль над производительностью с удобством высокого уровня и предоставляет гарантии
+безопасности.
+Он достигает этих целей, не требуя сборщика мусора или времени выполнения, что позволяет использовать библиотеки Rust как замену
+для C-библиотек.
+
+Первый выпуск Rust, 0.1, произошел в январе 2012 года, и в течение 3 лет развитие продвигалось настолько быстро, что до
+недавнего времени использование стабильных выпусков было затруднено, и вместо этого общий совет заключался в том, чтобы
+использовать последние сборки.
+
+15 мая 2015 года был выпущен Rust 1.0 с полной гарантией обратной совместимости. Усовершенствования времени компиляции и
+других аспектов компилятора в настоящее время доступны в ночных сборках. Rust приняла модель выпуска на поезде с регулярными выпусками каждые шесть недель. Rust 1.1 beta был доступен одновременно с выпуском Rust 1.0.
+
+Хотя Rust является языком относительно низкого уровня, Rust имеет некоторые функциональные концепции, которые обычно
+встречаются на языках более высокого уровня. Это делает Rust не только быстрым, но и простым и эффективным для ввода кода.
+
+
+```rust
+// Это однострочный комментарии
+//
+
+/// Так выглядит комментарий для документации
+/// # Examples
+///
+///
+/// let seven = 7
+///
+
+///////////////
+// 1. Основы //
+///////////////
+
+// Функции
+// `i32` это целочисленный знаковый тип 32-bit
+#[allow(dead_code)]
+fn add2(x: i32, y: i32) -> i32 {
+ // метод возвращает сумму x и y
+ x + y
+}
+
+// Главная функция программы
+#[allow(unused_variables)]
+#[allow(unused_assignments)]
+#[allow(dead_code)]
+fn main() {
+ // Числа //
+
+ // неизменяемая переменная
+ let x: i32 = 1;
+
+ // Суффиксы целое/дробное
+ let y: i32 = 13i32;
+ let f: f64 = 1.3f64;
+
+ // Автоматическое выявление типа данных
+ // В большинстве случаев компилятор Rust может вычислить
+ // тип переменной, поэтому
+ // вам не нужно писать явные аннотации типа.
+
+ let implicit_x = 1;
+ let implicit_f = 1.3;
+
+ // Арифметика
+ let sum = x + y + 13;
+
+ // Изменяемая переменная
+ let mut mutable = 1;
+ mutable = 4;
+ mutable += 2;
+
+ // Строки //
+
+ // Строковые литералы
+ let x: &str = "hello world!";
+
+ // Печать на консоль
+ println!("{} {}", f, x); // 1.3 hello world
+
+ // `String` – изменяемя строка
+ let s: String = "hello world".to_string();
+
+ // Строковый срез - неизменяемый вид в строки
+ // Это в основном неизменяемая пара указателей на строку -
+ // Это указатель на начало и конец строкового буфера
+
+ let s_slice: &str = &s;
+
+ println!("{} {}", s, s_slice); // hello world hello world
+
+ // Vectors/arrays //
+
+ // фиксированный массив
+ let four_ints: [i32; 4] = [1, 2, 3, 4];
+
+ // динамический массив
+ let mut vector: Vec<i32> = vec![1, 2, 3, 4];
+ vector.push(5);
+
+ // Срез - неизменяемое представление значений вектора
+ let slice: &[i32] = &vector;
+
+ // Используйте шаблон `{:?}`для печати отладочной информации структур с данными
+ println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
+
+ // Кортежи //
+
+ // Кортеж - это фиксированный набор.
+ // В нём могут находиться значения разных типов данных.
+ let x: (i32, &str, f64) = (1, "hello", 3.4);
+
+ // Инициализация группы переменных `let`
+ let (a, b, c) = x;
+ println!("{} {} {}", a, b, c); // 1 hello 3.4
+
+ // Доступ по индексу
+ println!("{}", x.1); // hello
+
+ //////////////
+ // 2. Типы //
+ //////////////
+
+ // Struct
+ struct Point {
+ x: i32,
+ y: i32,
+ }
+
+ let origin: Point = Point { x: 0, y: 0 };
+
+ // Структуры могут быть с безымянными полями ‘tuple struct’
+ struct Point2(i32, i32);
+
+ let origin2 = Point2(0, 0);
+
+ // Перечисление
+ enum Direction {
+ Left,
+ Right,
+ Up,
+ Down,
+ }
+
+ let up = Direction::Up;
+
+ // Перечисление с полями
+ enum OptionalI32 {
+ AnI32(i32),
+ Nothing,
+ }
+
+ let two: OptionalI32 = OptionalI32::AnI32(2);
+ let nothing = OptionalI32::Nothing;
+
+ // Обобщенные типы данных //
+
+ struct Foo<T> { bar: T }
+
+ // Частоиспользуемое перечисление стандартной библиотеки `Option`
+ enum Optional<T> {
+ SomeVal(T),
+ NoVal,
+ }
+
+ // Методы //
+
+ impl<T> Foo<T> {
+ fn get_bar(self) -> T {
+ self.bar
+ }
+ }
+
+ let a_foo = Foo { bar: 1 };
+ println!("{}", a_foo.get_bar()); // 1
+
+ // Типаж
+
+ trait Frobnicate<T> {
+ fn frobnicate(self) -> Option<T>;
+ }
+
+ impl<T> Frobnicate<T> for Foo<T> {
+ fn frobnicate(self) -> Option<T> {
+ Some(self.bar)
+ }
+ }
+
+ let another_foo = Foo { bar: 1 };
+ println!("{:?}", another_foo.frobnicate()); // Some(1)
+
+ /////////////////////////
+ // 3. Поиск по шаблону //
+ /////////////////////////
+
+ let foo = OptionalI32::AnI32(1);
+ match foo {
+ OptionalI32::AnI32(n) => println!("it’s an i32: {}", n),
+ OptionalI32::Nothing => println!("it’s nothing!"),
+ }
+
+ // Более сложный пример
+ struct FooBar { x: i32, y: OptionalI32 }
+ let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) };
+
+ match bar {
+ FooBar { x: 0, y: OptionalI32::AnI32(0) } =>
+ println!("The numbers are zero!"),
+ FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m =>
+ println!("The numbers are the same"),
+ FooBar { x: n, y: OptionalI32::AnI32(m) } =>
+ println!("Different numbers: {} {}", n, m),
+ FooBar { x: _, y: OptionalI32::Nothing } =>
+ println!("The second number is Nothing!"),
+ }
+
+ /////////////////////
+ // 4. Управление ходом выполнения программы //
+ /////////////////////
+
+ // `for` loops/iteration
+ let array = [1, 2, 3];
+ for i in array.iter() {
+ println!("{}", i);
+ }
+
+ // Отрезки
+ for i in 0u32..10 {
+ print!("{} ", i);
+ }
+ println!("");
+ // prints `0 1 2 3 4 5 6 7 8 9 `
+
+ // `if`
+ if 1 == 1 {
+ println!("Maths is working!");
+ } else {
+ println!("Oh no...");
+ }
+
+ // `if` as expression
+ let value = if true {
+ "good"
+ } else {
+ "bad"
+ };
+
+ // `while` loop
+ while 1 == 1 {
+ println!("The universe is operating normally.");
+ break;
+ }
+
+ // Infinite loop
+ loop {
+ println!("Hello!");
+ break;
+ }
+
+ /////////////////////////////////
+ // 5. Защита памяти и указатели //
+ /////////////////////////////////
+
+ // Владеющий указатель – такой указатель может быть только один
+ // Это значит, что при вызоде из блока переменная автоматически становится недействительной.
+ let mut mine: Box<i32> = Box::new(3);
+ *mine = 5; // dereference
+ // Здесь, `now_its_mine` получает во владение `mine`. Т.е. `mine` была перемещена.
+ let mut now_its_mine = mine;
+ *now_its_mine += 2;
+
+ println!("{}", now_its_mine); // 7
+ // println!("{}", mine);
+
+ // Ссылки - это неизменяемые указатели
+ // Если ссылка получает значения, то говорят, что она заимствует это значение.
+ // Такое значение не может быть изменено или перемещено.
+ let mut var = 4;
+ var = 3;
+ let ref_var: &i32 = &var;
+
+ println!("{}", var);
+ println!("{}", *ref_var);
+ // var = 5; // не скомпилируется
+ // *ref_var = 6; // и это
+
+ // Изменяемые ссылки
+ //
+ let mut var2 = 4;
+ let ref_var2: &mut i32 = &mut var2;
+ *ref_var2 += 2; // '*' используется для изменения значения
+
+ println!("{}", *ref_var2); // 6 , // var2 would not compile.
+ // ref_var2 имеет тип &mut i32, т.е. он содержит ссылку на i32, а не значение.
+ // var2 = 2; // не скомпилируется, т.к. эта переменная уже была заимствована ранее
+}
+
+```
+
+## Более подробная информация о языке
+
+Уже есть хорошие книги для изучающих Rust. Основным источником остаётся
+[The Rust Programming Language](http://doc.rust-lang.org/book/index.html)
+
+Для компиляции программ при изучении языка весьма удобно использовать
+[Rust playpen](http://play.rust-lang.org).
+Множество ресурсов на разных языках можно найти в [этом проекте](https://github.com/ctjhoa/rust-learning).