summaryrefslogtreecommitdiffhomepage
path: root/ru-ru
diff options
context:
space:
mode:
Diffstat (limited to 'ru-ru')
-rw-r--r--ru-ru/.directory4
-rw-r--r--ru-ru/asymptotic-notation-ru.html.markdown225
-rw-r--r--ru-ru/bash-ru.html.markdown346
-rw-r--r--ru-ru/bf.html.markdown1
-rw-r--r--ru-ru/c++-ru.html.markdown40
-rw-r--r--ru-ru/c-ru.html.markdown28
-rw-r--r--ru-ru/clojure-ru.html.markdown54
-rw-r--r--ru-ru/common-lisp-ru.html.markdown704
-rw-r--r--ru-ru/crystal-ru.html.markdown584
-rw-r--r--ru-ru/css-ru.html.markdown6
-rw-r--r--ru-ru/elixir-ru.html.markdown467
-rw-r--r--ru-ru/go-ru.html.markdown4
-rw-r--r--ru-ru/haml-ru.html.markdown233
-rw-r--r--ru-ru/haskell-ru.html.markdown3
-rw-r--r--ru-ru/html-ru.html.markdown3
-rw-r--r--ru-ru/java-ru.html.markdown3
-rw-r--r--ru-ru/javascript-ru.html.markdown4
-rw-r--r--ru-ru/jquery-ru.html.markdown127
-rw-r--r--ru-ru/kotlin-ru.html.markdown375
-rw-r--r--ru-ru/learnvisualbasic-ru.html.markdown284
-rw-r--r--ru-ru/linker-ru.html.markdown203
-rw-r--r--ru-ru/markdown-ru.html.markdown55
-rw-r--r--ru-ru/nim-ru.html.markdown285
-rw-r--r--ru-ru/objective-c-ru.html.markdown2
-rw-r--r--ru-ru/pascal-ru.html.markdown217
-rw-r--r--ru-ru/perl-ru.html.markdown30
-rw-r--r--ru-ru/php-composer-ru.html.markdown197
-rw-r--r--ru-ru/php-ru.html.markdown43
-rw-r--r--ru-ru/pyqt-ru.html.markdown86
-rw-r--r--ru-ru/python-ru.html.markdown1041
-rw-r--r--ru-ru/pythonlegacy-ru.html.markdown (renamed from ru-ru/python3-ru.html.markdown)225
-rw-r--r--ru-ru/ruby-ru.html.markdown192
-rw-r--r--ru-ru/rust-ru.html.markdown313
-rw-r--r--ru-ru/sql-ru.html.markdown120
-rw-r--r--ru-ru/swift-ru.html.markdown38
-rw-r--r--ru-ru/vim-ru.html.markdown2
-rw-r--r--ru-ru/yaml-ru.html.markdown189
37 files changed, 6035 insertions, 698 deletions
diff --git a/ru-ru/.directory b/ru-ru/.directory
deleted file mode 100644
index 4d20336b..00000000
--- a/ru-ru/.directory
+++ /dev/null
@@ -1,4 +0,0 @@
-[Dolphin]
-SortRole=size
-Timestamp=2015,10,31,18,6,13
-Version=3
diff --git a/ru-ru/asymptotic-notation-ru.html.markdown b/ru-ru/asymptotic-notation-ru.html.markdown
new file mode 100644
index 00000000..7fd02c47
--- /dev/null
+++ b/ru-ru/asymptotic-notation-ru.html.markdown
@@ -0,0 +1,225 @@
+---
+category: Algorithms & Data Structures
+name: Asymptotic Notation
+contributors:
+ - ["Jake Prather", "http://github.com/JakeHP"]
+ - ["Divay Prakash", "http://github.com/divayprakash"]
+translators:
+ - ["pru-mike", "http://github.com/pru-mike"]
+lang: ru-ru
+---
+
+# О-символика
+
+## Что это такое?
+
+О-символика, или асимптотическая запись, — это система символов, позволяющая
+оценить время выполнения алгоритма, устанавливая зависимость времени выполнения
+от увеличения объёма входных данных. Она также известна как оценка
+сложности алгоритмов. Станет ли алгоритм невероятно медленным, когда
+объём входных данных увеличится? Будет ли алгоритм выполняться достаточно быстро,
+если объём входных данных возрастёт? О-символика позволяет ответить на эти
+вопросы.
+
+## Можно ли по-другому найти ответы на эти вопросы?
+
+Один способ — это подсчитать число элементарных операций в зависимости от
+различных объёмов входных данных. Хотя это и приемлемое решение, тот объём
+работы, которого оно потребует, даже для простых алгоритмов делает его
+использование неоправданным.
+
+Другой способ — это измерить, какое время алгоритм потребует для завершения на
+различных объёмах входных данных. В то же время, точность и относительность
+этого метода (полученное время будет относиться только к той машине, на которой
+оно вычислено) зависит от среды выполнения: компьютерного аппаратного
+обеспечения, мощности процессора и т.д.
+
+## Виды О-символики
+
+В первом разделе этого документа мы определили, что О-символика
+позволяет оценивать алгоритмы в зависимости от изменения размера входных
+данных. Представим, что алгоритм — это функция f, n — размер входных данных и
+f(n) — время выполнения. Тогда для данного алгоритма f с размером входных
+данных n получим какое-то результирующее время выполнения f(n).
+Из этого можно построить график, где ось y — время выполнения, ось x — размер входных
+данных, а точки на графике — это время выполнения для заданного размера входных
+данных.
+
+С помощью О-символики можно оценить функцию или алгоритм
+несколькими различными способами. Например, можно оценить алгоритм исходя
+из нижней оценки, верхней оценки, тождественной оценки. Чаще всего встречается
+анализ на основе верхней оценки. Как правило не используется нижняя оценка,
+потому что она не подходит под планируемые условия. Отличный пример — алгоритмы
+сортировки, особенно добавление элементов в древовидную структуру. Нижняя оценка
+большинства таких алгоритмов может быть дана как одна операция. В то время как в
+большинстве случаев добавляемые элементы должны быть отсортированы
+соответствующим образом при помощи дерева, что может потребовать обхода целой
+ветви. Это и есть худший случай, для которого планируется верхняя оценка.
+
+### Виды функций, пределы и упрощения
+
+```
+Логарифмическая функция — log n
+Линейная функция — an + b
+Квадратичная функция — an^2 + bn +c
+Степенная функция — an^z + . . . + an^2 + a*n^1 + a*n^0, где z — константа
+Показательная функция — a^n, где a — константа
+```
+
+Приведены несколько базовых функций, используемых при определении сложности в
+различных оценках. Список начинается с самой медленно возрастающей функции
+(логарифм, наиболее быстрое время выполнения) и следует до самой быстро
+возрастающей функции (экспонента, самое медленное время выполнения). Отметим,
+что в то время, как «n», или размер входных данных, возрастает в каждой из этих функций,
+результат намного быстрее возрастает в квадратичной, степенной
+и показательной по сравнению с логарифмической и линейной.
+
+Крайне важно понимать, что при использовании описанной далее нотации необходимо
+использовать упрощённые выражения.
+Это означает, что необходимо отбрасывать константы и слагаемые младших порядков,
+потому что если размер входных данных (n в функции f(n) нашего примера)
+увеличивается до бесконечности (в пределе), тогда слагаемые младших порядков
+и константы становятся пренебрежительно малыми. Таким образом, если есть
+константа, например, размера 2^9001 или любого другого невообразимого размера,
+надо понимать, что её упрощение внесёт значительные искажения в точность
+оценки.
+
+Т.к. нам нужны упрощённые выражения, немного скорректируем нашу таблицу...
+
+```
+Логарифм — log n
+Линейная функция — n
+Квадратичная функция — n^2
+Степенная функция — n^z, где z — константа
+Показательная функция — a^n, где a — константа
+```
+
+### О Большое
+О Большое, записывается как **О**, — это асимптотическая запись для оценки худшего
+случая, или для ограничения заданной функции сверху. Это позволяет сделать
+_**асимптотическую оценку верхней границы**_ скорости роста времени выполнения
+алгоритма. Пусть `f(n)` — время выполнения алгоритма, а `g(n)` — заданная временная
+сложность, которая проверяется для алгоритма. Тогда `f(n)` — это O(g(n)), если
+существуют действительные константы c (c > 0) и n<sub>0</sub>, такие,
+что `f(n)` <= `c g(n)` выполняется для всех n, начиная с некоторого n<sub>0</sub> (n > n<sub>0</sub>).
+
+*Пример 1*
+
+```
+f(n) = 3log n + 100
+g(n) = log n
+```
+
+Является ли `f(n)` O(g(n))?
+Является ли `3 log n + 100` O(log n)?
+Посмотрим на определение О Большого:
+
+```
+3log n + 100 <= c * log n
+```
+
+Существуют ли константы c и n<sub>0</sub>, такие, что выражение верно для всех n > n<sub>0</sub>?
+
+```
+3log n + 100 <= 150 * log n, n > 2 (не определенно для n = 1)
+```
+
+Да! По определению О Большого `f(n)` является O(g(n)).
+
+*Пример 2*
+
+```
+f(n) = 3 * n^2
+g(n) = n
+```
+
+Является ли `f(n)` O(g(n))?
+Является ли `3 * n^2` O(n)?
+Посмотрим на определение О Большого:
+
+```
+3 * n^2 <= c * n
+```
+
+Существуют ли константы c и n<sub>0</sub>, такие, что выражение верно для всех n > n<sub>0</sub>?
+Нет, не существуют. `f(n)` НЕ ЯВЛЯЕТСЯ O(g(n)).
+
+### Омега Большое
+Омега Большое, записывается как **Ω**, — это асимптотическая запись для оценки
+лучшего случая, или для ограничения заданной функции снизу. Это позволяет сделать
+_**асимптотическую оценку нижней границы**_ скорости роста времени выполнения
+алгоритма.
+
+`f(n)` является Ω(g(n)), если существуют действительные константы
+c (c > 0) и n<sub>0</sub> (n<sub>0</sub> > 0), такие, что `f(n)` >= `c g(n)` для всех n > n<sub>0</sub>.
+
+### Примечание
+
+Асимптотические оценки, сделаные при помощи О Большого и Омега Большого, могут
+как являться, так и не являться точными. Для того, чтобы обозначить, что границы не
+являются асимптотически точными, используются записи О Малое и Омега Малое.
+
+### О Малое
+O Малое, записывается как **о**, — это асимптотическая запись для оценки верхней
+границы времени выполнения алгоритма при условии, что граница не является
+асимптотически точной.
+
+`f(n)` является o(g(n)), если можно подобрать такие действительные константы,
+что для всех c (c > 0) найдётся n<sub>0</sub> (n<sub>0</sub> > 0), так
+что `f(n)` < `c g(n)` выполняется для всех n (n > n<sub>0</sub>).
+
+Определения О-символики для О Большого и О Малого похожи. Главное отличие в том,
+что если f(n) = O(g(n)), тогда условие f(n) <= c g(n) выполняется, если _**существует**_
+константа c > 0, но если f(n) = o(g(n)), тогда условие f(n) < c g(n) выполняется
+для _**всех**_ констант c > 0.
+
+### Омега Малое
+Омега Малое, записывается как **ω**, — это асимптотическая запись для оценки
+верхней границы времени выполнения алгоритма при условии, что граница не является
+асимптотически точной.
+
+`f(n)` является ω(g(n)), если можно подобрать такие действительные константы,
+что для всех c (c > 0) найдётся n<sub>0</sub> (n<sub>0</sub> > 0), так
+что `f(n)` > `c g(n)` выполняется для всех n (n > n<sub>0</sub>).
+
+Определения Ω-символики и ω-символики похожи. Главное отличие в том, что
+если f(n) = Ω(g(n)), тогда условие f(n) >= c g(n) выполняется, если _**существует**_
+константа c > 0, но если f(n) = ω(g(n)), тогда условие f(n) > c g(n)
+выполняется для _**всех**_ констант c > 0.
+
+### Тета
+Тета, записывается как **Θ**, — это асимптотическая запись для оценки
+_***асимптотически точной границы***_ времени выполнения алгоритма.
+
+`f(n)` является Θ(g(n)), если для некоторых действительных
+констант c1, c2 и n<sub>0</sub> (c1 > 0, c2 > 0, n<sub>0</sub> > 0)
+`c1 g(n)` < `f(n)` < `c2 g(n)` для всех n (n > n<sub>0</sub>).
+
+∴ `f(n)` является Θ(g(n)) означает, что `f(n)` является O(g(n))
+и `f(n)` является Ω(g(n)).
+
+О Большое — основной инструмент для анализа сложности алгоритмов.
+Также см. примеры по ссылкам.
+
+### Заключение
+Такую тему сложно изложить кратко, поэтому обязательно стоит пройти по ссылкам и
+посмотреть дополнительную литературу. В ней даётся более глубокое описание с
+определениями и примерами.
+
+
+## Дополнительная литература
+
+* [Алгоритмы на Java](https://www.ozon.ru/context/detail/id/18319699/)
+* [Алгоритмы. Построение и анализ](https://www.ozon.ru/context/detail/id/33769775/)
+
+## Ссылки
+
+* [Оценки времени исполнения. Символ O()](http://algolist.manual.ru/misc/o_n.php)
+* [Асимптотический анализ и теория вероятностей](https://www.lektorium.tv/course/22903)
+
+## Ссылки (англ.)
+
+* [Algorithms, Part I](https://www.coursera.org/learn/algorithms-part1)
+* [Cheatsheet 1](http://web.mit.edu/broder/Public/asymptotics-cheatsheet.pdf)
+* [Cheatsheet 2](http://bigocheatsheet.com/)
+
diff --git a/ru-ru/bash-ru.html.markdown b/ru-ru/bash-ru.html.markdown
index 5e99afc2..ce918340 100644
--- a/ru-ru/bash-ru.html.markdown
+++ b/ru-ru/bash-ru.html.markdown
@@ -11,29 +11,40 @@ contributors:
- ["Rahil Momin", "https://github.com/iamrahil"]
- ["Gregrory Kielian", "https://github.com/gskielian"]
- ["Etan Reisner", "https://github.com/deryni"]
+ - ["Jonathan Wang", "https://github.com/Jonathansw"]
+ - ["Leo Rudberg", "https://github.com/LOZORD"]
+ - ["Betsy Lorton", "https://github.com/schbetsy"]
+ - ["John Detter", "https://github.com/jdetter"]
+ - ["Harry Mumford-Turner", "https://github.com/harrymt"]
+ - ["Martin Nicholson", "https://github.com/mn113"]
translators:
- ["Andrey Samsonov", "https://github.com/kryzhovnik"]
- - ["Andre Polykanine", "https://github.com/Oire"]
+ - ["Andre Polykanine", "https://github.com/Menelion"]
filename: LearnBash-ru.sh
lang: ru-ru
---
-Bash - это командная оболочка unix (unix shell), которая распространялась как оболочка для операционной системы GNU и используется в качестве оболочки по умолчанию для Linux и Mac OS X.
-Почти все нижеприведенные примеры могут быть частью shell-скриптов или исполнены напрямую в shell.
+Bash — это командная оболочка unix, которая распространялась как оболочка
+для операционной системы GNU и используется в качестве оболочки по умолчанию
+для Linux и Mac OS X.
+Почти все нижеприведённые примеры могут быть частью shell-скриптов
+или исполнены напрямую в shell.
[Подробнее.](http://www.gnu.org/software/bash/manual/bashref.html)
```bash
#!/bin/bash
-# Первая строка скрипта - это shebang, который сообщает системе, как исполнять
-# этот скрипт: http://en.wikipedia.org/wiki/Shebang_(Unix)
-# Как вы уже поняли, комментарии начинаются с #. Shebang - тоже комментарий.
+# Первая строка скрипта — это шебанг, который сообщает системе, как исполнять
+# этот скрипт: https://ru.wikipedia.org/wiki/Шебанг_(Unix)
+# Как вы уже поняли, комментарии начинаются с «#». Шебанг — тоже комментарий.
# Простой пример hello world:
echo Hello world!
# Отдельные команды начинаются с новой строки или разделяются точкой с запятой:
echo 'Это первая строка'; echo 'Это вторая строка'
+# => Это первая строка
+# => Это вторая строка
# Вот так объявляется переменная:
VARIABLE="Просто строка"
@@ -41,103 +52,234 @@ VARIABLE="Просто строка"
# но не так:
VARIABLE = "Просто строка"
# Bash решит, что VARIABLE - это команда, которую он должен исполнить,
-# и выдаст ошибку, потому что не сможет найти ее.
+# и выдаст ошибку, потому что не сможет найти её.
# и не так:
VARIABLE= 'Просто строка'
-# Тут Bash решит, что 'Просто строка' - это команда, которую он должен исполнить,
-# и выдаст ошибку, потому что не сможет найти такой команды
+# Тут Bash решит, что 'Просто строка' — это команда, которую он должен
+# исполнить, и выдаст ошибку, потому что не сможет найти такой команды
# (здесь 'VARIABLE=' выглядит как присвоение значения переменной,
# но только в контексте исполнения команды 'Просто строка').
# Использование переменой:
-echo $VARIABLE
-echo "$VARIABLE"
-echo '$VARIABLE'
-# Когда вы используете переменную - присваиваете, экспортируете и т.д. -
+echo $VARIABLE # => Просто строка
+echo "$VARIABLE" # => Просто строка
+echo '$VARIABLE' # => $Variable
+# Когда вы используете переменную — присваиваете, экспортируете и т.д. —
# пишите её имя без $. А для получения значения переменной используйте $.
# Заметьте, что ' (одинарные кавычки) не раскрывают переменные в них.
-# Подстановка строк в переменные
-echo ${VARIABLE/Просто/A}
-# Это выражение заменит первую встреченную подстроку "Просто" на "A"
+# Раскрытие параметров ${ }:
+echo ${Variable} # => Просто строка
+# Это простое использование раскрытия параметров
+# Раскрытие параметров получает значение переменной.
+# Оно «раскрывает», или печатает это значение.
+# ̶Значение можно изменить во время раскрытия.
+# Ниже приведены другие модификации при раскрытии параметров.
+
+# Замена подстрок в переменных
+echo ${Variable/Просто/Это} # => Это строка
+# Заменит первое вхождение «Просто» на «Это»
# Взять подстроку из переменной
LENGTH=7
-echo ${VARIABLE:0:LENGTH}
-# Это выражение вернет только первые 7 символов переменной VARIABLE
+echo ${VARIABLE:0:LENGTH} # => Просто
+# Это выражение вернёт только первые 7 символов переменной VARIABLE
+echo ${Variable: -5} # => трока
+# Вернёт последние 5 символов (обратите внимание на пробел перед «-5»)
+
+# Длина строки
+echo ${#Variable} # => 13
-# Значение по умолчанию
-echo ${FOO:-"DefaultValueIfFOOIsMissingOrEmpty"}
+# Значение переменной по умолчанию
+echo ${FOO:-"ЗначениеПоУмолчаниюЕслиFooПустаИлиНеНайдена"}
+# => ЗначениеПоУмолчаниюЕслиFooПустаИлиНеНайдена
# Это сработает при отсутствующем значении (FOO=) и пустой строке (FOO="");
-# ноль (FOO=0) вернет 0.
-# Заметьте, что в любом случае значение самой переменной FOO не изменится.
+# ноль (FOO=0) вернёт 0.
+# Заметьте, что в любом случае это лишь вернёт значение по умолчанию,
+# а значение самой переменной FOO не изменится.
+
+# Объявить массив из 6 элементов
+array0=(один два три четыре пять шесть)
+# Вывести первый элемент
+echo $array0 # => "один"
+# Вывести первый элемент
+echo ${array0[0]} # => "один"
+# Вывести все элементы
+echo ${array0[@]} # => "один два три четыре пять шесть"
+# Вывести число элементов
+echo ${#array0[@]} # => "6"
+# Вывести число символов в третьем элементе
+echo ${#array0[2]} # => "3"
+# Вывести 2 элемента, начиная с четвёртого
+echo ${array0[@]:3:2} # => "четыре пять"
+# Вывести все элементы, каждый на своей строке
+for i in "${array0[@]}"; do
+ echo "$i"
+done
+
+# Раскрытие скобок { }
+# Используется для создания произвольных строк
+echo {1..10} # => 1 2 3 4 5 6 7 8 9 10
+echo {a..z} # => a b c d e f g h i j k l m n o p q r s t u v w x y z
+# Выведет диапазон от начального до конечного значения
# Встроенные переменные:
# В bash есть полезные встроенные переменные, например
-echo "Последнее возвращенное значение: $?"
-echo "PID скрипта: $$"
-echo "Количество аргументов: $#"
-echo "Аргументы скрипта: $@"
+echo "Значение, возвращённое последней программой: $?"
+echo "Идентификатор процесса скрипта: $$"
+echo "Число аргументов, переданных скрипту: $#"
+echo "Все аргументы, переданные скрипту: $@"
echo "Аргументы скрипта, распределённые по отдельным переменным: $1 $2..."
-# Чтение аргументов из устройста ввода:
+# Теперь, когда мы знаем, как выводить и использовать переменные,
+# давайте изучим некоторые другие основы Bash!
+
+# Текущая директория доступна по команде `pwd`.
+# `pwd` расшифровывается как «print working directory», т.е.
+# «напечатать рабочую директорию».
+# Мы также можем использовать встроенную переменную `$PWD`.
+# Заметьте, следующие выражения эквивалентны:
+echo "Я в $(pwd)" # выполняет `pwd` и раскрывает вывод
+echo "Я в $PWD" # раскрывает переменную
+
+# Если вы получаете слишком много информации в терминале или из скрипта,
+# команда `clear` очистит экран
+clear
+# Очистить экран можно также с помощью Ctrl+L
+
+# Чтение аргументов с устройства ввода:
echo "Как Вас зовут?"
read NAME # Обратите внимание, что нам не нужно определять новую переменную
echo Привет, $NAME!
# У нас есть обычная структура if:
# наберите 'man test' для получения подробной информации о форматах условия
-if [ $NAME -ne $USER ]
+if [ $NAME != $USER ]
then
echo "Имя не совпадает с именем пользователя"
else
echo "Имя совпадает с именем пользователя"
fi
+# Истинно, если значение $Name не совпадает с текущим именем пользователя
-# Примечание: если $Name пустой, bash интерпретирует код как:
-if [ -ne $USER ]
+# Примечание: если $Name пуста, bash интерпретирует код так:
+if [ != $USER ]
# а это ошибочная команда
-# поэтому такие переменные нужно использовать так:
-if [ "$Name" -ne $USER ] ...
-# когда $Name пустой, bash видит код как:
-if [ "" -ne $USER ] ...
+# поэтому «безопасный» способ использовать пустые переменные в Bash таков:
+if [ "$Name" != $USER ] ...
+# при этом, когда $Name пуста, bash видит код так:
+if [ "" != $USER ] ...
# что работает правильно
# Также есть условное исполнение
echo "Исполнится всегда" || echo "Исполнится, если первая команда завершится ошибкой"
+# => Исполнится всегда
echo "Исполнится всегда" && echo "Исполнится, если первая команда выполнится удачно"
+# => Исполнится всегда
+# => Исполнится, если первая команда выполнится удачно
-# Можно использовать && и || в выражениях if, когда нужно несколько пар скобок:
-if [ $NAME == "Steve" ] && [ $AGE -eq 15 ]
+
+# Чтобы использовать && и || в выражениях if, нужно несколько пар скобок:
+if [ $NAME == "Стив" ] && [ $AGE -eq 15 ]
+then
+ echo "Исполнится, если $NAME равно Стив И $AGE равно 15."
+fi
+
+if [ $NAME == "Дания" ] || [ $NAME == "Зак" ]
then
- echo "Исполнится, если $NAME равно Steve И $AGE равно 15."
+ echo "Исполнится, если $NAME равно Дания ИЛИ Зак."
fi
-if [ $NAME == "Daniya" ] || [ $NAME == "Zach" ]
+# Есть ещё оператор «=~», который проверяет строку
+# на соответствие регулярному выражению:
+Email=me@example.com
+if [[ "$Email" =~ [a-z]+@[a-z]{2,}\.(com|net|org) ]]
then
- echo "Исполнится, если $NAME равно Daniya ИЛИ Zach."
+ echo "адрес корректный!"
fi
+# Обратите внимание, что =~ работает только внутри
+# двойных квадратных скобок [[ ]],
+# которые несколько отличаются от одинарных скобок [ ].
+# Для более подробной информации см. http://www.gnu.org/software/bash/manual/bashref.html#Conditional-Constructs.
+
+# Переопределить команду «ping» как псевдоним для отправки только пяти пакетов
+alias ping='ping -c 5'
+# Экранировать псевдоним и использовать команду под своим именем вместо него
+\ping 192.168.1.1
+# Вывести все псевдонимы
+alias -p
# Выражения обозначаются таким форматом:
-echo $(( 10 + 5 ))
+echo $(( 10 + 5 )) # => 15
-# В отличие от других языков программирования, Bash - это командная оболочка,
+# В отличие от других языков программирования, Bash — это командная оболочка,
# а значит, работает в контексте текущей директории.
# Вы можете просматривать файлы и директории в текущей директории командой ls:
-ls
+ls # перечисляет файлы и поддиректории в текущей директории
-# У этой команды есть опции:
+# У этой команды есть параметры:
ls -l # Показать каждый файл и директорию на отдельной строке
+ls -t # сортирует содержимое по дате последнего изменения (в обратном порядке)
+ls -R # Рекурсивно выполняет `ls` по данной директории и всем её поддиректориям
# Результат предыдущей команды может быть направлен на вход следующей.
# Команда grep фильтрует ввод по шаблону.
-# Так мы можем просмотреть только *.txt файлы в текущей директории:
+# Так мы можем просмотреть только *.txt-файлы в текущей директории:
ls -l | grep "\.txt"
+# Для вывода файлов в стандартный поток используйте `cat`:
+cat file.txt
+
+# С помощью `cat` мы также можем читать файлы:
+Contents=$(cat file.txt)
+echo "НАЧАЛО ФАЙЛА\n$Contents\nКОНЕЦ ФАЙЛА" # «\n» выводит символ перевода на новую строку
+# => НАЧАЛО ФАЙЛА
+# => [Содержимое file.txt]
+# => КОНЕЦ ФАЙЛА
+
+# Для копирования файлов и директорий из одного места в другое используйте `cp`.
+# `cp` создаёт новые версии исходных элементов,
+# так что редактирование копии не повлияет на оригинал (и наоборот).
+# Обратите внимание, что команда перезапишет целевой элемент, если он уже существует.
+cp srcFile.txt clone.txt
+cp -r srcDirectory/ dst/ # рекурсивное копирование
+
+# Если вам нужно обмениваться файлами между компьютерами, посмотрите в сторону `scp` или `sftp`.
+# `scp` ведёт себя очень похоже на `cp`.
+# `sftp` более интерактивна.
+
+# Для перемещения файлов и директорий из одного места в другое используйте `mv`.
+# Команда `mv` похожа на `cp`, но она удаляет исходный элемент.
+# `mv` также можно использовать для переименования файлов!
+mv s0urc3.txt dst.txt # Извините, тут были Leet-хакеры...
+
+# Поскольку Bash работает в контексте текущей директории, вам может понадобиться
+# запустить команду в другой директории.
+# Для изменения местоположения у нас есть `cd`:
+cd ~ # Перейти в домашнюю директорию
+cd # Также переходит в домашнюю директорию
+cd .. # Перейти на уровень вверх
+ # (например, из /home/username/Downloads в /home/username)
+cd /home/username/Documents # перейти в указанную директорию
+cd ~/Documents/.. # Всё ещё в домашней директории. Так ведь??
+cd - # Перейти в последнюю директорию
+# => /home/username/Documents
+
+# Для работы по директориям используйте субоболочки
+(echo "Сначала я здесь: $PWD") && (cd someDir; echo "А теперь я тут: $PWD")
+pwd # всё ещё в первой директории
+
+# Для создания новых директорий используйте `mkdir`.
+mkdir myNewDir
+# Флаг `-p` указывает, что нужно создать все промежуточные директории, если нужно.
+mkdir -p myNewDir/with/intermediate/directories
+# Если промежуточные директории до этого не существовали,
+# вышеприведённая команда без флага `-p` вернёт ошибку
+
# Вы можете перенаправить ввод и вывод команды (stdin, stdout и stderr).
-# Следующая команда означает: читать из stdin, пока не встретится ^EOF$, и
-# перезаписать hello.py следующим строками (до строки "EOF"):
+# Прочитать из stdin, пока не встретится ^EOF$, и
+# перезаписать hello.py следующими строками (до строки "EOF"):
cat > hello.py << EOF
#!/usr/bin/env python
from __future__ import print_function
@@ -147,23 +289,25 @@ print("#stderr", file=sys.stderr)
for line in sys.stdin:
print(line, file=sys.stdout)
EOF
+# Если первый «EOF» не заключён в кавычки, переменные будут раскрыты
# Запуск hello.py с разными вариантами перенаправления потоков
# стандартных ввода, вывода и ошибок:
-python hello.py < "input.in"
-python hello.py > "output.out"
-python hello.py 2> "error.err"
-python hello.py > "output-and-error.log" 2>&1
-python hello.py > /dev/null 2>&1
+python hello.py < "input.in" # передать input.in в качестве ввода в скрипт
+python hello.py > "output.out" # передать вывод скрипта в output.out
+python hello.py 2> "error.err" # передать вывод ошибок в error.err
+python hello.py > "output-and-error.log" 2>&1 # передать вывод скрипта и ошибок в output-and-error.log
+python hello.py > /dev/null 2>&1 # передать вывод скрипта и ошибок в «чёрную дыру» /dev/null, т.е., без вывода
# Поток ошибок перезапишет файл, если этот файл существует,
-# поэтому, если вы хотите дописывать файл, используйте ">>":
+# поэтому, если вы хотите дописывать файл, используйте «>>»:
python hello.py >> "output.out" 2>> "error.err"
-# Переписать output.txt, дописать error.err и сосчитать строки:
+# Перезаписать output.txt, дописать error.err и сосчитать строки:
info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err
wc -l output.out error.err
-# Запустить команду и вывести ее файловый дескриптор (смотрите: man fd)
+# Запустить команду и вывести её файловый дескриптор (например, /dev/fd/123)
+# См. man fd
echo <(echo "#helloworld")
# Перезаписать output.txt строкой "#helloworld":
@@ -172,40 +316,49 @@ echo "#helloworld" > output.out
echo "#helloworld" | cat > output.out
echo "#helloworld" | tee output.out >/dev/null
-# Подчистить временные файлы с подробным выводом ('-i' - интерактивый режим)
+# Подчистить временные файлы с подробным выводом ('-i' — интерактивный режим)
+# ВНИМАНИЕ: команду `rm` отменить нельзя
rm -v output.out error.err output-and-error.log
+rm -r tempDir/ # рекурсивное удаление
# Команды могут быть подставлены в строку с помощью $( ):
# следующие команды выводят число файлов и директорий в текущей директории.
echo "Здесь $(ls | wc -l) элементов."
-# То же самое можно сделать с использованием обратных кавычек,
+# То же самое можно сделать с использованием обратных кавычек «``»,
# но они не могут быть вложенными, поэтому предпочтительно использовать $( ).
echo "Здесь `ls | wc -l` элементов."
# В Bash есть структура case, которая похожа на switch в Java и C++:
case "$VARIABLE" in
- # Перечислите шаблоны для условий, которые хотите отловить
+ # Перечислите шаблоны для условий, которые хотите выполнить
0) echo "Тут ноль.";;
1) echo "Тут один.";;
*) echo "Это не пустое значение.";;
esac
-# Цикл for перебирает элементы переданные в аргументе:
+# Цикл for перебирает элементы по количеству аргументов:
# Содержимое $VARIABLE будет напечатано три раза.
for VARIABLE in {1..3}
do
echo "$VARIABLE"
done
+# => 1
+# => 2
+# => 3
+
-# Или с использованием "традиционного" синтаксиса цикла for:
+# Или с использованием «традиционного» синтаксиса цикла for:
for ((a=1; a <= 3; a++))
do
echo $a
done
+# => 1
+# => 2
+# => 3
# Цикл for можно использовать для действий с файлами.
-# Запустим команду 'cat' для файлов file1 и file2
+# Запустим команду «cat» для файлов file1 и file2
for VARIABLE in file1 file2
do
cat "$VARIABLE"
@@ -221,52 +374,89 @@ done
# Цикл while:
while [ true ]
do
- echo "тело цикла здесь..."
+ echo "Здесь тело цикла..."
break
done
+# => Здесь тело цикла...
-# Вы можете определять функции
+# Вы также можете определять функции
# Определение:
function foo ()
{
- echo "Аргументы работают также, как аргументы скрипта: $@"
- echo "и: $1 $2..."
+ echo "Аргументы работают так же, как и аргументы скрипта: $@"
+ echo "И так: $1 $2..."
echo "Это функция"
return 0
}
+# Вызовем функцию `foo` с двумя аргументами, arg1 и arg2:
+foo arg1 arg2
+# => Аргументы работают так же, как и аргументы скрипта: arg1 arg2
+# => И так: arg1 arg2...
+# => Это функция
# или просто
bar ()
{
- echo "Другой способ определить функцию!"
+ echo "Другой способ определять функции!"
return 0
}
+# Вызовем функцию `bar` без аргументов:
+bar # => Другой способ определять функции!
# Вызов функции
-foo "Мое имя" $NAME
+foo "Меня зовут" $NAME
# Есть много полезных команд, которые нужно знать:
# напечатать последние 10 строк файла file.txt
tail -n 10 file.txt
+
# напечатать первые 10 строк файла file.txt
head -n 10 file.txt
+
# отсортировать строки file.txt
sort file.txt
-# отобрать или наоборот пропустить повторяющиеся строки (с опцией -d отбирает)
+
+# отобрать или наоборот пропустить повторяющиеся строки (с параметром `-d` отбирает строки)
uniq -d file.txt
-# напечатать только первую колонку перед символом ','
+
+# напечатать только первый столбец перед символом «,»
cut -d ',' -f 1 file.txt
-# заменить каждое 'okay' на 'great' в файле file.txt (regex поддерживается)
-sed -i 's/okay/great/g' file.txt
-# вывести в stdout все строки из file.txt, совпадающие с шаблоном regex;
-# этот пример выводит строки, которые начинаются на "foo" и оканчиваются "bar"
+
+# заменить каждое вхождение «хорошо» на «прекрасно» в файле file.txt
+# (поддерживаются регулярные выражения)
+sed -i 's/хорошо/прекрасно/g' file.txt
+
+# вывести в stdout все строки из file.txt, соответствующие регулярному выражению
+# этот пример выводит строки, которые начинаются на «foo» и оканчиваются на «bar»
grep "^foo.*bar$" file.txt
-# передайте опцию -c чтобы вывести число строк, в которых совпал шаблон
+
+# Передайте параметр `-c`, чтобы вывести лишь число строк,
+# соответствующих регулярному выражению
grep -c "^foo.*bar$" file.txt
-# чтобы искать по строке, а не шаблону regex, используйте fgrep (или grep -F)
+
+# Ниже приведены другие полезные параметры:
+grep -r "^foo.*bar$" someDir/ # рекурсивный `grep`
+grep -n "^foo.*bar$" file.txt # задаются номера строк
+grep -rI "^foo.*bar$" someDir/ # рекурсивный `grep` с игнорированием двоичных файлов
+
+# Выполнить тот же изначальный поиск, но удалив строки, содержащие «baz»
+grep "^foo.*bar$" file.txt | grep -v "baz"
+
+# чтобы искать непосредственно по строке, а не в соответствии
+# с регулярным выражением, используйте fgrep (или grep -F):
fgrep "^foo.*bar$" file.txt
-# Читайте встроенную документацию оболочки Bash командой 'help':
+# Команда `trap` позволяет выполнить некую команду, когда ваш скрипт
+# принимает определённый Posix-сигнал. В следующем примере `trap` выполнит `rm`,
+# если скрипт примет один из трёх перечисленных сигналов.
+trap "rm $TEMP_FILE; exit" SIGHUP SIGINT SIGTERM
+
+# `sudo` используется для выполнения команд с правами суперпользователя
+NAME1=$(whoami)
+NAME2=$(sudo whoami)
+echo "Был $NAME1, затем стал более мощным $NAME2"
+
+# Читайте встроенную документацию оболочки Bash командой `help`:
help
help help
help for
@@ -274,18 +464,18 @@ help return
help source
help .
-# Читайте Bash man-документацию
+# Читайте man-документацию Bash командой `man`:
apropos bash
man 1 bash
man bash
-# Читайте документацию info (? для помощи)
+# Читайте документацию info (? для справки)
apropos info | grep '^info.*('
man info
info info
info 5 info
-# Читайте bash info документацию:
+# Читайте info-документацию Bash:
info bash
info bash 'Bash Features'
info bash 6
diff --git a/ru-ru/bf.html.markdown b/ru-ru/bf.html.markdown
index 20f0fa56..d2e74e8f 100644
--- a/ru-ru/bf.html.markdown
+++ b/ru-ru/bf.html.markdown
@@ -1,5 +1,6 @@
---
language: bf
+filename: learnbf-ru.bf
contributors:
- ["Prajit Ramachandran", "http://prajitr.github.io/"]
- ["Mathias Bynens", "http://mathiasbynens.be/"]
diff --git a/ru-ru/c++-ru.html.markdown b/ru-ru/c++-ru.html.markdown
index 0cf580d5..3acfafa3 100644
--- a/ru-ru/c++-ru.html.markdown
+++ b/ru-ru/c++-ru.html.markdown
@@ -43,11 +43,11 @@ int main(int argc, char** argv)
// Аргументы командной строки, переданные в программу, хранятся в переменных
// argc и argv, так же, как и в C.
// argc указывает на количество аргументов,
- // а argv является массивом C-подобных строк (char*), который непосредсвенно
+ // а argv является массивом C-подобных строк (char*), который непосредственно
// содержит аргументы.
// Первым аргументом всегда передается имя программы.
- // argc и argv могут быть опущены, если вы не планируете работать с аругментами
- // коммандной строки.
+ // argc и argv могут быть опущены, если вы не планируете работать с аргументами
+ // командной строки.
// Тогда сигнатура функции будет иметь следующий вид: int main()
// Возвращаемое значение 0 указывает на успешное завершение программы.
@@ -162,7 +162,7 @@ void foo()
int main()
{
- // Включает все функци из пространства имен Second в текущую область видимости.
+ // Включает все функции из пространства имен Second в текущую область видимости.
// Обратите внимание, что простой вызов foo() больше не работает,
// так как теперь не ясно, вызываем ли мы foo из пространства имен Second, или
// из глобальной области видимости.
@@ -304,7 +304,7 @@ someFun(tempObjectFun()); // Выполняет версию с временн
basic_string(const basic_string& other);
basic_string(basic_string&& other);
-// Идея в том, что если мы конструируем новую строку из временного объекта (который
+// Идея в том, что если мы конструируем новую строку из временного объекта (который
// так или иначе будет уничтожен), мы можем использовать более эффективный конструктор,
// который "спасает" части этой временной строки. Эта концепция была названа
// "move semantics".
@@ -329,7 +329,7 @@ ECarTypes GetPreferredCarType()
}
// На момент выхода C++11 есть простой способ назначения типа перечисления, что
-// полезно в случае сериализации данных и преобразований между конечным типом и
+// полезно в случае сериализации данных и преобразований между конечным типом и
// соответствующими константами.
enum ECarTypes : uint8_t
{
@@ -453,7 +453,7 @@ void Dog::print() const
Dog::~Dog()
{
- cout << "Goodbye " << name << "\n";
+ std::cout << "Goodbye " << name << "\n";
}
int main() {
@@ -471,6 +471,7 @@ int main() {
// членам\методам без открытых или защищенных методов для этого.
class OwnedDog : public Dog {
+public:
void setOwner(const std::string& dogsOwner);
// Переопределяем поведение функции печати для всех OwnedDog. Смотрите
@@ -521,7 +522,7 @@ public:
// по умолчанию (0, 0)
Point() { };
- // Следующий синтаксис известен как список инициализации и является верным способом
+ // Следующий синтаксис известен как список инициализации и является верным способом
// инициализировать значения членов класса.
Point (double a, double b) :
x(a),
@@ -582,10 +583,10 @@ public:
// Во время компиляции компилятор фактически генерирует копии каждого шаблона
// с замещенными параметрами, поэтому полное определение класса должно присутствовать
-// при каждом вызове. Именно поэтому классы шаблонов полностью определены в
+// при каждом вызове. Именно поэтому шаблоны классов полностью определены в
// заголовочных файлах.
-// Чтобы создать экземпляр класса шаблона на стеке:
+// Чтобы создать экземпляр шаблона класса на стеке:
Box<int> intBox;
// и вы можете использовать его, как и ожидалось:
@@ -605,7 +606,7 @@ boxOfBox.insert(intBox);
// http://en.wikipedia.org/wiki/Typename
// (да-да, это ключевое слово имеет собственную страничку на вики).
-// Аналогичным образом, шаблонная функция:
+// Аналогичным образом, шаблон функции:
template<class T>
void barkThreeTimes(const T& input)
{
@@ -622,7 +623,7 @@ Dog fluffy;
fluffy.setName("Fluffy");
barkThreeTimes(fluffy); // Печатает "Fluffy barks" три раза.
-//Параметры шаблона не должны быть классами:
+// Параметры шаблона не должны быть классами:
template<int Y>
void printMessage() {
cout << "Learn C++ in " << Y << " minutes!" << endl;
@@ -680,7 +681,7 @@ catch (...)
// некоторого ресурса неразрывно совмещается с инициализацией, а освобождение -
// с уничтожением объекта.
-// Чтобы понять, на сколько это полезно,
+// Чтобы понять, насколько это полезно,
// рассмотрим функцию, которая использует обработчик файлов в С:
void doSomethingWithAFile(const char* filename)
{
@@ -793,10 +794,10 @@ void doSomethingWithAFile(const std::string& filename)
// Весь идиоматический код на С++ широко использует RAII для всех ресурсов.
// Дополнительные примеры включат:
// - Использование памяти unique_ptr и shared_ptr
-// - Контейнеры - стандартная библиотека связанных списков, векторы
+// - Контейнеры - стандартная библиотека связанных списков, векторы
// (т.е. самоизменяемые массивы), хэш-таблицы и все остальное автоматически
// уничтожается сразу же, когда выходит за пределы области видимости.
-// - Ипользование мьютексов lock_guard и unique_lock
+// - Использование мьютексов lock_guard и unique_lock
// Контейнеры с пользовательскими классами в качестве ключей требуют
// сравнивающих функций в самом объекте или как указатель на функцию. Примитивы
@@ -853,7 +854,7 @@ pt2 = nullptr; // Устанавливает pt2 в null.
// '=' != '=' != '='!
// Вызывает Foo::Foo(const Foo&) или некий вариант (смотрите "move semantics")
-// копирования конструктора.
+// конструктора копирования.
Foo f2;
Foo f1 = f2;
@@ -886,7 +887,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/c-ru.html.markdown b/ru-ru/c-ru.html.markdown
index ab4be57e..cc68d620 100644
--- a/ru-ru/c-ru.html.markdown
+++ b/ru-ru/c-ru.html.markdown
@@ -11,7 +11,7 @@ lang: ru-ru
Что ж, Си всё ещё является лидером среди современных высокопроизводительных языков.
-Для большинствоа программистов, Си – это самый низкоуровневый язык на котором они когда-либо писали,
+Для большинства программистов, Си – это самый низкоуровневый язык на котором они когда-либо писали,
но этот язык даёт больше, чем просто повышение производительности.
Держите это руководство в памяти и вы сможете использовать Си максимально эффективно.
@@ -77,7 +77,7 @@ int main() {
// sizeof(obj) возвращает размер объекта obj в байтах.
printf("%zu\n", sizeof(int)); // => 4 (на большинстве машин int занимает 4 байта)
- // Если аргуметом sizeof будет выражение, то этот аргумент вычисляется
+ // Если аргументом sizeof будет выражение, то этот аргумент вычисляется
// ещё во время компиляции кода (кроме динамических массивов).
int a = 1;
// size_t это беззнаковый целый тип который использует как минимум 2 байта
@@ -170,7 +170,7 @@ int main() {
!0; // => 1
1 && 1; // => 1 (логическое И)
0 && 1; // => 0
- 0 || 1; // => 1 (лигическое ИЛИ)
+ 0 || 1; // => 1 (логическое ИЛИ)
0 || 0; // => 0
// Битовые операторы
@@ -229,7 +229,7 @@ int main() {
switch (some_integral_expression) {
case 0: // значения должны быть целыми константами (и могут быть выражениями)
do_stuff();
- break; // если не написать break; то управление будет передено следующему блоку
+ break; // если не написать break; то управление будет передано следующему блоку
case 1:
do_something_else();
break;
@@ -247,7 +247,7 @@ int main() {
// Каждое выражение в Си имеет тип, но вы можете привести один тип к другому,
// если хотите (с некоторыми искажениями).
- int x_hex = 0x01; // Вы можете назначать переменные с помощью шеснадцатеричного кода.
+ int x_hex = 0x01; // Вы можете назначать переменные с помощью шестнадцатеричного кода.
// Приведение типов будет пытаться сохранять цифровые значения.
printf("%d\n", x_hex); // => Prints 1
@@ -288,14 +288,14 @@ int main() {
// Для того, чтобы получить значение по адресу, напечатайте * перед именем.
// Да, * используется при объявлении указателя и для получении значения по адресу
// немного запутано, но вы привыкнете.
- printf("%d\n", *px); // => Напечаатет 0, значение перемененной x
+ printf("%d\n", *px); // => Напечатает 0, значение перемененной x
// Вы также можете изменять значение, на которое указывает указатель.
(*px)++; // Инкрементирует значение на которое указывает px на единицу
printf("%d\n", *px); // => Напечатает 1
printf("%d\n", x); // => Напечатает 1
- // Массивы удобно использовать для болшого количества однотипных данных.
+ // Массивы удобно использовать для большого количества однотипных данных.
int x_array[20];
int xx;
for (xx = 0; xx < 20; xx++) {
@@ -308,7 +308,7 @@ int main() {
// Это работает, потому что при обращении к имени массива возвращается
// указатель на первый элемент.
// Например, когда массив передаётся в функцию или присваивается указателю, он
- // невявно преобразуется в указатель.
+ // неявно преобразуется в указатель.
// Исключения: когда массив является аргументом для оператор '&':
int arr[10];
int (*ptr_to_arr)[10] = &arr; // &arr не является 'int *'!
@@ -335,7 +335,7 @@ int main() {
// Работа с памятью с помощью указателей может давать неожиданные и
// непредсказуемые результаты.
- printf("%d\n", *(my_ptr + 21)); // => Напечатает кто-нибудь-знает-что?
+ printf("%d\n", *(my_ptr + 21)); // => Напечатает кто-нибудь знает, что?
// Скорей всего программа вылетит.
// Когда вы закончили работать с памятью, которую ранее выделили, вам необходимо
@@ -353,7 +353,7 @@ int main() {
// Это не работает, если строка является массивом
// (потенциально задаваемой с помощью строкового литерала)
- // который находиться в перезаписываемой части памяти:
+ // который находится в перезаписываемой части памяти:
char foo[] = "foo";
foo[0] = 'a'; // это выполнится и строка теперь "aoo"
@@ -426,7 +426,7 @@ void function_1() {
// Можно получить доступ к структуре и через указатель
(*my_rec_ptr).width = 30;
- // ... или ещё лучше: используйте оператор -> для лучшей читабельночти
+ // ... или ещё лучше: используйте оператор -> для лучшей читабельности
my_rec_ptr->height = 10; // то же что и "(*my_rec_ptr).height = 10;"
}
@@ -457,7 +457,7 @@ int area(const rect *r) {
void str_reverse_through_pointer(char *str_in) {
// Определение функции через указатель.
- void (*f)(char *); // Сигнатура должна полность совпадать с целевой функцией.
+ void (*f)(char *); // Сигнатура должна полностью совпадать с целевой функцией.
f = &str_reverse; // Присвоить фактический адрес (во время исполнения)
// "f = str_reverse;" тоже будет работать.
//Имя функции (как и массива) возвращает указатель на начало.
@@ -471,13 +471,13 @@ void str_reverse_through_pointer(char *str_in) {
Лучше всего найдите копию [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language)
Это **книга** написанная создателями Си. Но будьте осторожны, она содержит идеи которые больше не считаются хорошими.
-Другой хороший ресурс: [Learn C the hard way](http://c.learncodethehardway.org/book/).
+Другой хороший ресурс: [Learn C the hard way](http://learncodethehardway.org/c/).
Если у вас появился вопрос, почитайте [compl.lang.c Frequently Asked Questions](http://c-faq.com).
Очень важно использовать правильные отступы и ставить пробелы в нужных местах.
Читаемый код лучше чем красивый или быстрый код.
-Чтобы научиться писать хороший код, почитайте [Linux kernel coding stlye](https://www.kernel.org/doc/Documentation/CodingStyle).
+Чтобы научиться писать хороший код, почитайте [Linux kernel coding style](https://www.kernel.org/doc/Documentation/CodingStyle).
Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья.
diff --git a/ru-ru/clojure-ru.html.markdown b/ru-ru/clojure-ru.html.markdown
index 451da312..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)
@@ -321,7 +321,7 @@ keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
; Также модуль может быть импортирован формой require
(require 'clojure.string)
-; После этого модуль становится доступе в текущем пространстве имен,
+; После этого модуль становится доступен в текущем пространстве имен,
; а вызов его функций может быть осуществлен указанием полного имени функции:
(clojure.string/blank? "") ; => true
@@ -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/css-ru.html.markdown b/ru-ru/css-ru.html.markdown
index 2e2d40b7..e0e5e30b 100644
--- a/ru-ru/css-ru.html.markdown
+++ b/ru-ru/css-ru.html.markdown
@@ -116,7 +116,7 @@ element:visited {}
/* или еще не проходил по ней */
element:link {}
-/* выбранное поле воода (input) */
+/* выбранное поле ввода (input) */
element:focus {}
@@ -132,7 +132,7 @@ selector {
width: 200px; /* пиксели */
font-size: 20pt; /* пункты */
width: 5cm; /* сантиметры */
- min-width: 50mm; /* милиметры */
+ min-width: 50mm; /* миллиметры */
max-width: 5in; /* дюймы */
height: 0.2vh; /* умножается на высоту окна браузера (CSS3) */
width: 0.4vw; /* умножается на ширину окна браузера (CSS3) */
@@ -235,7 +235,7 @@ p { property: value !important; }
## Совместимость
-Несмотря на то, что большая часть функций CSS2 (а также CSS3) подеррживается всеми
+Несмотря на то, что большая часть функций CSS2 (а также CSS3) поддерживается всеми
браузерами и устройствами, не забывайте проверять совместимость CSS-правил
с современными браузерами.
diff --git a/ru-ru/elixir-ru.html.markdown b/ru-ru/elixir-ru.html.markdown
new file mode 100644
index 00000000..c8c2c060
--- /dev/null
+++ b/ru-ru/elixir-ru.html.markdown
@@ -0,0 +1,467 @@
+---
+language: elixir
+contributors:
+ - ["Joao Marques", "http://github.com/mrshankly"]
+ - ["Dzianis Dashkevich", "https://github.com/dskecse"]
+ - ["Ryan Plant", "https://github.com/ryanplant-au"]
+translator:
+ - ["Ev Bogdanov", "https://github.com/evbogdanov"]
+filename: learnelixir-ru.ex
+lang: ru-ru
+---
+
+Elixir — современный функциональный язык программирования, который работает на
+виртуальной машине Erlang. Elixir полностью совместим с Erlang, но обладает
+дружелюбным синтаксисом и предлагает больше возможностей.
+
+```elixir
+
+# Однострочные комментарии начинаются с символа решётки.
+
+# Для многострочных комментариев отдельного синтаксиса нет,
+# поэтому просто используйте несколько однострочных комментариев.
+
+# Запустить интерактивную Elixir-консоль (аналог `irb` в Ruby) можно
+# при помощи команды `iex`.
+# Чтобы скомпилировать модуль, воспользуйтесь командой `elixirc`.
+
+# Обе команды будут работать из терминала, если вы правильно установили Elixir.
+
+## ---------------------------
+## -- Базовые типы
+## ---------------------------
+
+# Числа
+3 # целое число
+0x1F # целое число
+3.0 # число с плавающей запятой
+
+# Атомы, которые являются нечисловыми константами. Они начинаются с символа `:`.
+:hello # атом
+
+# Кортежи, которые хранятся в памяти последовательно.
+{1,2,3} # кортеж
+
+# Получить доступ к элементу кортежа мы можем с помощью функции `elem`:
+elem({1, 2, 3}, 0) #=> 1
+
+# Списки, которые реализованы как связные списки.
+[1,2,3] # список
+
+# У каждого непустого списка есть голова (первый элемент списка)
+# и хвост (все остальные элементы списка):
+[head | tail] = [1,2,3]
+head #=> 1
+tail #=> [2,3]
+
+# В Elixir, как и в Erlang, знак `=` служит для сопоставления с образцом,
+# а не для операции присваивания.
+#
+# Это означает, что выражение слева от знака `=` (образец) сопоставляется с
+# выражением справа.
+#
+# Сопоставление с образцом позволило нам получить голову и хвост списка
+# в примере выше.
+
+# Если выражения слева и справа от знака `=` не удаётся сопоставить, будет
+# брошена ошибка. Например, если кортежи разных размеров.
+{a, b, c} = {1, 2} #=> ** (MatchError)
+
+# Бинарные данные
+<<1,2,3>>
+
+# Вы столкнётесь с двумя видами строк:
+"hello" # Elixir-строка (заключена в двойные кавычки)
+'hello' # Erlang-строка (заключена в одинарные кавычки)
+
+# Все строки представлены в кодировке UTF-8:
+"привет" #=> "привет"
+
+# Многострочный текст
+"""
+Я текст на несколько
+строк.
+"""
+#=> "Я текст на несколько\nстрок.\n"
+
+# Чем Elixir-строки отличаются от Erlang-строк? Elixir-строки являются бинарными
+# данными.
+<<?a, ?b, ?c>> #=> "abc"
+# Erlang-строка — это на самом деле список.
+[?a, ?b, ?c] #=> 'abc'
+
+# Оператор `?` возвращает целое число, соответствующее данному символу.
+?a #=> 97
+
+# Для объединения бинарных данных (и Elixir-строк) используйте `<>`
+<<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>>
+"hello " <> "world" #=> "hello world"
+
+# Для объединения списков (и Erlang-строк) используйте `++`
+[1,2,3] ++ [4,5] #=> [1,2,3,4,5]
+'hello ' ++ 'world' #=> 'hello world'
+
+# Диапазоны записываются как `начало..конец` (оба включительно)
+1..10 #=> 1..10
+
+# Сопоставление с образцом применимо и для диапазонов:
+lower..upper = 1..10
+[lower, upper] #=> [1, 10]
+
+# Карты (известны вам по другим языкам как ассоциативные массивы, словари, хэши)
+genders = %{"david" => "male", "gillian" => "female"}
+genders["david"] #=> "male"
+
+# Для карт, где ключами выступают атомы, доступен специальный синтаксис
+genders = %{david: "male", gillian: "female"}
+genders.gillian #=> "female"
+
+## ---------------------------
+## -- Операторы
+## ---------------------------
+
+# Математические операции
+1 + 1 #=> 2
+10 - 5 #=> 5
+5 * 2 #=> 10
+10 / 2 #=> 5.0
+
+# В Elixir оператор `/` всегда возвращает число с плавающей запятой.
+
+# Для целочисленного деления применяйте `div`
+div(10, 2) #=> 5
+
+# Для получения остатка от деления к вашим услугам `rem`
+rem(10, 3) #=> 1
+
+# Булевые операторы: `or`, `and`, `not`.
+# В качестве первого аргумента эти операторы ожидают булевое значение.
+true and true #=> true
+false or true #=> true
+1 and true #=> ** (BadBooleanError)
+
+# Elixir также предоставляет `||`, `&&` и `!`, которые принимают аргументы
+# любого типа. Всё, кроме `false` и `nil`, считается `true`.
+1 || true #=> 1
+false && 1 #=> false
+nil && 20 #=> nil
+!true #=> false
+
+# Операторы сравнения: `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<`, `>`
+1 == 1 #=> true
+1 != 1 #=> false
+1 < 2 #=> true
+
+# Операторы `===` и `!==` более строгие. Разница заметна, когда мы сравниваем
+# числа целые и с плавающей запятой:
+1 == 1.0 #=> true
+1 === 1.0 #=> false
+
+# Elixir позволяет сравнивать значения разных типов:
+1 < :hello #=> true
+
+# При сравнении разных типов руководствуйтесь следующим правилом:
+# число < атом < ссылка < функция < порт < процесс < кортеж < список < строка
+
+## ---------------------------
+## -- Порядок выполнения
+## ---------------------------
+
+# Условный оператор `if`
+if false do
+ "Вы этого никогда не увидите"
+else
+ "Вы увидите это"
+end
+
+# Противоположный ему условный оператор `unless`
+unless true do
+ "Вы этого никогда не увидите"
+else
+ "Вы увидите это"
+end
+
+# Помните сопоставление с образцом?
+# Многие конструкции в Elixir построены вокруг него.
+
+# `case` позволяет сравнить выражение с несколькими образцами:
+case {:one, :two} do
+ {:four, :five} ->
+ "Этот образец не совпадёт"
+ {:one, x} ->
+ "Этот образец совпадёт и присвоит переменной `x` значение `:two`"
+ _ ->
+ "Этот образец совпадёт с чем угодно"
+end
+
+# Символ `_` называется анонимной переменной. Используйте `_` для значений,
+# которые в текущем выражении вас не интересуют. Например, вам интересна лишь
+# голова списка, а хвост вы желаете проигнорировать:
+[head | _] = [1,2,3]
+head #=> 1
+
+# Для лучшей читаемости вы можете написать:
+[head | _tail] = [:a, :b, :c]
+head #=> :a
+
+# `cond` позволяет проверить сразу несколько условий за раз.
+# Используйте `cond` вместо множественных операторов `if`.
+cond do
+ 1 + 1 == 3 ->
+ "Вы меня никогда не увидите"
+ 2 * 5 == 12 ->
+ "И меня"
+ 1 + 2 == 3 ->
+ "Вы увидите меня"
+end
+
+# Обычно последним условием идёт `true`, которое выполнится, если все предыдущие
+# условия оказались ложны.
+cond do
+ 1 + 1 == 3 ->
+ "Вы меня никогда не увидите"
+ 2 * 5 == 12 ->
+ "И меня"
+ true ->
+ "Вы увидите меня (по сути, это `else`)"
+end
+
+# Обработка ошибок происходит в блоках `try/catch`.
+# Elixir также поддерживает блок `after`, который выполнится в любом случае.
+try do
+ throw(:hello)
+catch
+ message -> "Поймана ошибка с сообщением #{message}."
+after
+ IO.puts("Я выполнюсь всегда")
+end
+#=> Я выполнюсь всегда
+# "Поймана ошибка с сообщением hello."
+
+## ---------------------------
+## -- Модули и функции
+## ---------------------------
+
+# Анонимные функции (обратите внимание на точку при вызове функции)
+square = fn(x) -> x * x end
+square.(5) #=> 25
+
+# Анонимные функции принимают клозы и гарды.
+#
+# Клозы (от англ. clause) — варианты исполнения функции.
+#
+# Гарды (от англ. guard) — охранные выражения, уточняющие сопоставление с
+# образцом в функциях. Гарды следуют после ключевого слова `when`.
+f = fn
+ x, y when x > 0 -> x + y
+ x, y -> x * y
+end
+
+f.(1, 3) #=> 4
+f.(-1, 3) #=> -3
+
+# В Elixir много встроенных функций.
+# Они доступны в текущей области видимости.
+is_number(10) #=> true
+is_list("hello") #=> false
+elem({1,2,3}, 0) #=> 1
+
+# Вы можете объединить несколько функций в модуль. Внутри модуля используйте `def`,
+# чтобы определить свои функции.
+defmodule Math do
+ def sum(a, b) do
+ a + b
+ end
+
+ def square(x) do
+ x * x
+ end
+end
+
+Math.sum(1, 2) #=> 3
+Math.square(3) #=> 9
+
+# Чтобы скомпилировать модуль Math, сохраните его в файле `math.ex`
+# и наберите в терминале: `elixirc math.ex`
+
+defmodule PrivateMath do
+ # Публичные функции начинаются с `def` и доступны из других модулей.
+ def sum(a, b) do
+ do_sum(a, b)
+ end
+
+ # Приватные функции начинаются с `defp` и доступны только внутри своего модуля.
+ defp do_sum(a, b) do
+ a + b
+ end
+end
+
+PrivateMath.sum(1, 2) #=> 3
+PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError)
+
+# Функции внутри модуля тоже принимают клозы и гарды
+defmodule Geometry do
+ def area({:rectangle, w, h}) do
+ w * h
+ end
+
+ def area({:circle, r}) when is_number(r) do
+ 3.14 * r * r
+ end
+end
+
+Geometry.area({:rectangle, 2, 3}) #=> 6
+Geometry.area({:circle, 3}) #=> 28.25999999999999801048
+Geometry.area({:circle, "not_a_number"}) #=> ** (FunctionClauseError)
+
+# Из-за неизменяемых переменных в Elixir важную роль играет рекурсия
+defmodule Recursion do
+ def sum_list([head | tail], acc) do
+ sum_list(tail, acc + head)
+ end
+
+ def sum_list([], acc) do
+ acc
+ end
+end
+
+Recursion.sum_list([1,2,3], 0) #=> 6
+
+# Модули в Elixir поддерживают атрибуты.
+# Атрибуты бывают как встроенные, так и ваши собственные.
+defmodule MyMod do
+ @moduledoc """
+ Это встроенный атрибут
+ """
+
+ @my_data 100 # А это ваш атрибут
+ IO.inspect(@my_data) #=> 100
+end
+
+# Одна из фишек языка — оператор `|>`
+# Он передаёт выражение слева в качестве первого аргумента функции справа:
+Range.new(1,10)
+|> Enum.map(fn x -> x * x end)
+|> Enum.filter(fn x -> rem(x, 2) == 0 end)
+#=> [4, 16, 36, 64, 100]
+
+## ---------------------------
+## -- Структуры и исключения
+## ---------------------------
+
+# Структуры — это расширения поверх карт, привносящие в Elixir значения по
+# умолчанию, проверки на этапе компиляции и полиморфизм.
+defmodule Person do
+ defstruct name: nil, age: 0, height: 0
+end
+
+joe_info = %Person{ name: "Joe", age: 30, height: 180 }
+#=> %Person{age: 30, height: 180, name: "Joe"}
+
+# Доступ к полю структуры
+joe_info.name #=> "Joe"
+
+# Обновление поля структуры
+older_joe_info = %{ joe_info | age: 31 }
+#=> %Person{age: 31, height: 180, name: "Joe"}
+
+# Блок `try` с ключевым словом `rescue` используется для обработки исключений
+try do
+ raise "какая-то ошибка"
+rescue
+ RuntimeError -> "перехвачена ошибка рантайма"
+ _error -> "перехват любой другой ошибки"
+end
+#=> "перехвачена ошибка рантайма"
+
+# У каждого исключения есть сообщение
+try do
+ raise "какая-то ошибка"
+rescue
+ x in [RuntimeError] ->
+ x.message
+end
+#=> "какая-то ошибка"
+
+## ---------------------------
+## -- Параллелизм
+## ---------------------------
+
+# Параллелизм в Elixir построен на модели акторов. Для написания
+# параллельной программы нам понадобятся три вещи:
+# 1. Создание процессов
+# 2. Отправка сообщений
+# 3. Приём сообщений
+
+# Новый процесс создаётся функцией `spawn`, которая принимает функцию
+# в качестве аргумента.
+f = fn -> 2 * 2 end #=> #Function<erl_eval.20.80484245>
+spawn(f) #=> #PID<0.40.0>
+
+# `spawn` возвращает идентификатор процесса (англ. process identifier, PID).
+# Вы можете использовать PID для отправки сообщений этому процессу. Сообщения
+# отправляются через оператор `send`. А для приёма сообщений используется
+# механизм `receive`:
+
+# Блок `receive do` ждёт сообщений и обработает их, как только получит. Блок
+# `receive do` обработает лишь одно полученное сообщение. Чтобы обработать
+# несколько сообщений, функция, содержащая блок `receive do`, должна рекурсивно
+# вызывать себя.
+
+defmodule Geometry do
+ def area_loop do
+ receive do
+ {:rectangle, w, h} ->
+ IO.puts("Площадь = #{w * h}")
+ area_loop()
+ {:circle, r} ->
+ IO.puts("Площадь = #{3.14 * r * r}")
+ area_loop()
+ end
+ end
+end
+
+# Скомпилируйте модуль и создайте процесс
+pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0>
+# Альтернативно
+pid = spawn(Geometry, :area_loop, [])
+
+# Отправьте сообщение процессу
+send pid, {:rectangle, 2, 3}
+#=> Площадь = 6
+# {:rectangle,2,3}
+
+send pid, {:circle, 2}
+#=> Площадь = 12.56
+# {:circle,2}
+
+# Кстати, интерактивная консоль — это тоже процесс.
+# Чтобы узнать текущий PID, воспользуйтесь встроенной функцией `self`
+self() #=> #PID<0.27.0>
+
+## ---------------------------
+## -- Агенты
+## ---------------------------
+
+# Агент — это процесс, который следит за некоторым изменяющимся значением.
+
+# Создайте агента через `Agent.start_link`, передав ему функцию.
+# Начальным состоянием агента будет значение, которое эта функция возвращает.
+{ok, my_agent} = Agent.start_link(fn -> ["красный", "зелёный"] end)
+
+# `Agent.get` принимает имя агента и анонимную функцию `fn`, которой будет
+# передано текущее состояние агента. В результате вы получите то, что вернёт
+# анонимная функция.
+Agent.get(my_agent, fn colors -> colors end) #=> ["красный", "зелёный"]
+
+# Похожим образом вы можете обновить состояние агента
+Agent.update(my_agent, fn colors -> ["синий" | colors] end)
+```
+
+## Ссылки
+
+* [Официальный сайт](http://elixir-lang.org)
+* [Шпаргалка по языку](http://media.pragprog.com/titles/elixir/ElixirCheat.pdf)
+* [Книга "Programming Elixir"](https://pragprog.com/book/elixir/programming-elixir)
+* [Книга "Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/)
+* [Книга "Programming Erlang: Software for a Concurrent World"](https://pragprog.com/book/jaerlang2/programming-erlang)
diff --git a/ru-ru/go-ru.html.markdown b/ru-ru/go-ru.html.markdown
index 6c8622cc..37592258 100644
--- a/ru-ru/go-ru.html.markdown
+++ b/ru-ru/go-ru.html.markdown
@@ -35,7 +35,7 @@ package main
// Import предназначен для указания зависимостей этого файла.
import (
"fmt" // Пакет в стандартной библиотеке Go
- "io/ioutil" // Реализация функций ввод/ввывода.
+ "io/ioutil" // Реализация функций ввод/вывода.
"net/http" // Да, это веб-сервер!
"strconv" // Конвертирование типов в строки и обратно
m "math" // Импортировать math под локальным именем m.
@@ -270,7 +270,7 @@ func learnErrorHandling() {
// c – это тип данных channel (канал), объект для конкурентного взаимодействия.
func inc(i int, c chan int) {
- c <- i + 1 // когда channel слева, <- являтся оператором "отправки".
+ c <- i + 1 // когда channel слева, <- является оператором "отправки".
}
// Будем использовать функцию inc для конкурентной инкрементации чисел.
diff --git a/ru-ru/haml-ru.html.markdown b/ru-ru/haml-ru.html.markdown
new file mode 100644
index 00000000..c2f8852e
--- /dev/null
+++ b/ru-ru/haml-ru.html.markdown
@@ -0,0 +1,233 @@
+---
+language: haml
+filename: learnhaml-ru.haml
+contributors:
+ - ["Simon Neveu", "https://github.com/sneveu"]
+ - ["Vasiliy Petrov", "https://github.com/Saugardas"]
+translators:
+ - ["Vasiliy Petrov", "https://github.com/Saugardas"]
+lang: ru-ru
+---
+
+Haml - язык разметки (в основном используемый с Ruby), с помощью которого могут быть легко описаны HTML-документы.
+Он является популярной альтернативой используемому в Rails шаблонизатору (.erb), и позволяет вставлять Ruby-код в вашу разметку.
+
+Haml убирает избыточность закрывающих тегов благодаря отступам.
+В результате получается меньшая по размерам, хорошо структурированная, логичная и читаемая разметка.
+
+Вы можете использовать Haml и вне Ruby-проекта. Установите гем Haml и используйте командную строку для конвертирования html-файлов:
+
+```shell
+$ haml input_file.haml output_file.html
+```
+
+
+```haml
+/ -------------------------------------------
+/ Отступы
+/ -------------------------------------------
+
+/
+ Отступы являются важным элементом синтаксиса, поэтому они должны быть
+ одинаковыми во всём документе. Обычно используют два пробела,
+ но это не является обязательным правилом - можно использовать любое
+ количество пробелов для отступов. Главное, чтобы это количество было
+ одинаковым во всём документе.
+
+
+/ -------------------------------------------
+/ Комментарии
+/ -------------------------------------------
+
+/ Комментари начинается с символа косой черты.
+
+/
+ Для написания многострочного комментария расположите ваш комментарий
+ на следующем уровне вложенности от символа косой черты
+
+-# "Скрытый" комментарий. Этот комментарий не попадёт в результирующий документ
+
+
+/ -------------------------------------------
+/ Элементы HTML
+/ -------------------------------------------
+
+/ Чтобы написать тег, используйте символ процента (%) и название тега
+%body
+ %header
+ %nav
+
+/ Обратите внимание на отсутствие закрывающих тегов. Код выше выведет:
+ <body>
+ <header>
+ <nav></nav>
+ </header>
+ </body>
+
+/
+ Так как тег div используется очень часто, его можно опустить.
+ Можно указать только имя класса или идентификатора (. или #)
+ Например код:
+
+%div.my_class
+ %div#my_id
+
+/ Можно записать:
+.my_class
+ #my_id
+
+/ Для добавления контента в тег, просто добавьте текст после объявления тега
+%h1 Заголовок
+
+/ Для многострочного содержания используйте отступы
+%p
+ Многострочное содержание
+ в две строки.
+
+/
+ Амперсанд - равно (&=) обрабатывают Ruby код также, как и без амперсанда,
+ но HTML-символы в результате будут экранированы. Например:
+
+%p
+ &= "Да & да"
+
+/ выведет 'Да &amp; да'
+
+/
+ Чтобы выполнять Ruby-код без экранрования, можно использовать
+ "восклицательный знак" и "равно" (!=)
+
+%p
+ != "Тег абзаца <p></p>"
+
+/ выведет 'Тег абзаца <p></p>'
+
+/ CSS - классы могут быть добавлены через точку от определения тега
+%div.foo.bar
+
+/ Или с помощью хеша атрибутов
+%div{ :class => 'foo bar' }
+
+/ Хеш атрибутов может быть добавлен для любого тега
+%a{ :href => '#', :class => 'bar', :title => 'Bar' }
+
+/ Для булевых атрибутов просто присвойте значение 'true'
+%input{ :selected => true }
+
+/ Для data - атрибутов присвойте ключу :data хеш с данными
+%div{ :data => { :attribute => 'foo' } }
+
+/ Для Ruby версии 1.9 или выше, можно использовать новый синтаксис хешей
+%div{ data: { attribute: 'foo' } }
+
+/ Также можно использовать HTML-синтаксис атрибутов
+%a(href='#' title='bar')
+
+/ Можно использовать оба варианта одновременно
+%a(href='#'){ title: @my_class.title }
+
+
+/ -------------------------------------------
+/ Включение Ruby
+/ -------------------------------------------
+
+/ Для включения Ruby кода используйте знак "равно"
+
+%h1= book.name
+
+%p
+ = book.author
+ = book.publisher
+
+
+/ Для выполнения Ruby кода без вывода в HTML, используйте знак дефиса
+- books = ['book 1', 'book 2', 'book 3']
+
+/
+ Можно выполнять любой Ruby код, например с блоками.
+ Закрывающий "end" не нужен, так как они будут закрыты автоматически,
+ основываясь на вложенности.
+
+- books.shuffle.each_with_index do |book, index|
+ %h1= book
+
+ - if book do
+ %p This is a book
+
+/ Добавление списка
+%ul
+ %li
+ =item1
+ =item2
+
+/ -------------------------------------------
+/ Пример таблицы с классами Bootstrap'a
+/ -------------------------------------------
+
+%table.table.table-hover
+ %thead
+ %tr
+ %th Header 1
+ %th Header 2
+
+ %tr
+ %td Value1
+ %td value2
+
+ %tfoot
+ %tr
+ %td
+ Foot value
+
+
+/ -------------------------------------------
+/ Интерполяция Ruby кода
+/ -------------------------------------------
+
+/ Ruby код может быть интерполирован в текст с помощью #{}
+%p Ваша самая любимая игра - #{best_game}
+
+/ Тоже самое, что и:
+%p= "Ваша самая любимая игра - #{best_game}"
+
+
+/ -------------------------------------------
+/ Фильтры
+/ -------------------------------------------
+
+/
+ Фильтры передают связанный блок текста в соотвествующую
+ фильтрующую программу и возвращают результат в Haml
+ Фильтр обозначается двоеточием и названием фильтра:
+
+/ Markdown filter
+:markdown
+ # Заголовк
+
+ Текст **внутри** *блока*
+
+/ Код выше будет скомпилирован в
+<h1>Заголовок</h1>
+
+<p>Текст <strong>внутри</strong> <em>блока</em></p>
+
+/ Javascript - фильтр
+:javascript
+ console.log('This is inline <script>');
+
+/ скомпилируется в:
+<script>
+ console.log('This is inline <script>');
+</script>
+
+/
+ Существует множество типов фильров (:markdown, :javascript, :coffee,
+ :css, :ruby и так далее). Вы можете определить собственный фильтр c
+ помощью Haml::Filters.
+
+```
+
+## Дополнительные ресурсы
+
+- [О Haml](https://haml.ru) - Хорошее введение, описывает преимущества Haml.
+- [Документация](https://haml.ru/documentation/) - Документация Haml на русском языке.
diff --git a/ru-ru/haskell-ru.html.markdown b/ru-ru/haskell-ru.html.markdown
index e15fe6b7..b1b8eb79 100644
--- a/ru-ru/haskell-ru.html.markdown
+++ b/ru-ru/haskell-ru.html.markdown
@@ -1,5 +1,6 @@
---
language: Haskell
+filename: haskell-ru.hs
contributors:
- ["Adit Bhargava", "http://adit.io"]
translators:
@@ -66,7 +67,7 @@ not False -- True
----------------------------------------------------
--- Списки и Кортежи
+-- 2. Списки и Кортежи
----------------------------------------------------
-- Все элементы списка в Haskell
diff --git a/ru-ru/html-ru.html.markdown b/ru-ru/html-ru.html.markdown
index 5cf95fc4..120981b9 100644
--- a/ru-ru/html-ru.html.markdown
+++ b/ru-ru/html-ru.html.markdown
@@ -1,10 +1,11 @@
---
language: html
-filename: learnhtml.html
+filename: learnhtml-ru.html
contributors:
- ["Christophe THOMAS", "https://github.com/WinChris"]
translators:
- ["Lana Tim", "https://github.com/LanaTim"]
+lang: ru-ru
---
HTML расшифровывается как Hypertext Markup Language(гипертекстовый язык разметки).
diff --git a/ru-ru/java-ru.html.markdown b/ru-ru/java-ru.html.markdown
index a1a5cdfc..1aff801c 100644
--- a/ru-ru/java-ru.html.markdown
+++ b/ru-ru/java-ru.html.markdown
@@ -1,12 +1,13 @@
---
language: java
+filename: LearnJava-ru.java
contributors:
- ["Jake Prather", "http://github.com/JakeHP"]
- ["Madison Dickson", "http://github.com/mix3d"]
translators:
- ["Sergey Gaykov", "https://github.com/gaykov"]
-filename: LearnJavaRu.java
lang: ru-ru
+
---
Java - это объектно-ориентированный язык программирования общего назначения,
diff --git a/ru-ru/javascript-ru.html.markdown b/ru-ru/javascript-ru.html.markdown
index 1f1ffce6..c31c6994 100644
--- a/ru-ru/javascript-ru.html.markdown
+++ b/ru-ru/javascript-ru.html.markdown
@@ -1,7 +1,7 @@
---
language: javascript
contributors:
- - ["Adam Brenecki", "http://adam.brenecki.id.au"]
+ - ["Leigh Brenecki", "https://leigh.net.au"]
- ["Ariel Krakowski", "http://www.learneroo.com"]
filename: javascript-ru.js
translators:
@@ -420,7 +420,7 @@ myObj.__proto__ = myPrototype;
myObj.meaningOfLife; // = 42
// Для функций это тоже работает.
-myObj.myFunc(); // = "Привет, мир!"
+myObj.myFunc(); // = "привет, мир!"
// Если интерпретатор не найдёт свойство в прототипе, то продожит поиск
// в прототипе прототипа и так далее.
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/kotlin-ru.html.markdown b/ru-ru/kotlin-ru.html.markdown
new file mode 100644
index 00000000..85f44c96
--- /dev/null
+++ b/ru-ru/kotlin-ru.html.markdown
@@ -0,0 +1,375 @@
+---
+language: kotlin
+filename: LearnKotlin-ru.kt
+lang: ru-ru
+contributors:
+ - ["S Webber", "https://github.com/s-webber"]
+translators:
+ - ["Vadim Toptunov", "https://github.com/VadimToptunov"]
+---
+
+Kotlin - статически типизированный язык для JVM, Android и браузера. Язык полностью совместим c Java.
+[Более детальная информация здесь.](https://kotlinlang.org/)
+
+```kotlin
+// Однострочные комментарии начинаются с //
+/*
+А вот так выглядят многострочные комментарии.
+*/
+
+// Ключевое слово "package" действует и используется // абсолютно также, как и в Java.
+package com.learnxinyminutes.kotlin
+
+/*
+Точкой входа в программу на языке Kotlin является функция "main".
+Приведенная ниже функция передает массив, содержащий любые аргументы из командной строки.
+*/
+fun main(args: Array<String>) {
+ /*
+ Объявление значений производится с помощью или "var", или "val".
+ Значения объявленные с помощью "val" не могут быть изменены или перезаписаны, в то время как объявленные с помощью "var" - могут.
+ */
+ val fooVal = 10 // мы не можем потом изменить значение fooVal на какое-либо иное
+ var fooVar = 10
+ fooVar = 20 // значение fooVar затем может быть изменено.
+
+ /*
+ В большинстве случаев Kotlin самостоятельно может определить тип переменной, поэтому нам не нужно явно указывать его каждый раз.
+ Мы можем явно объявить тип переменной следующим образом:
+ */
+ val foo: Int = 7
+
+ /*
+ Строки могут быть представлены тем же образом, что и в Java.
+ Для экранирования используется обратный слэш.
+ */
+ val fooString = "My String Is Here!"
+ val barString = "Printing on a new line?\nNo Problem!"
+ val bazString = "Do you want to add a tab?\tNo Problem!"
+ println(fooString)
+ println(barString)
+ println(bazString)
+
+ /*
+ Необработанная строка разделяется тройной кавычкой (""").
+ Необработанные строки могут содержать символы новой строки и любые другие символы.
+ */
+ val fooRawString = """
+fun helloWorld(val name : String) {
+ println("Hello, world!")
+}
+"""
+ println(fooRawString)
+
+ /*
+ Строки могут содержать в себе шаблонные выражения.
+ Шаблонные выражения начинаются со знака доллара ($).
+ */
+ val fooTemplateString = "$fooString has ${fooString.length} characters"
+ println(fooTemplateString)
+
+ /*
+ Переменная, которая содержит null должна быть явно обозначена как nullable.
+ Переменная может быть обозначена как nullable с помощью добавления знака вопроса(?) к ее типу.
+ Мы можем получить доступ к nullable переменной используя оператор ?. .
+ Для того, чтобы указать иное значение, если переменная является null, мы используем оператор ?: .
+ */
+ var fooNullable: String? = "abc"
+ println(fooNullable?.length) // => 3
+ println(fooNullable?.length ?: -1) // => 3
+ fooNullable = null
+ println(fooNullable?.length) // => null
+ println(fooNullable?.length ?: -1) // => -1
+
+ /*
+ Функции могут быть объявлены с помощью ключевого слова "fun".
+ Аргументы функции указываются в скобках после имени функции.
+ Аргументы функции также могу иметь и значение по умолчанию.
+ Если требуется, то тип возвращаемого функцией значения, может быть указан после аргументов.
+ */
+ fun hello(name: String = "world"): String {
+ return "Hello, $name!"
+ }
+ println(hello("foo")) // => Hello, foo!
+ println(hello(name = "bar")) // => Hello, bar!
+ println(hello()) // => Hello, world!
+
+ /*
+ Параметр функции может быть отмечен с помощью ключевого слова "vararg", для того чтобы позволить аргументам попасть в функцию.
+ */
+ fun varargExample(vararg names: Int) {
+ println("Argument has ${names.size} elements")
+ }
+ varargExample() // => Argument has 0 elements
+ varargExample(1) // => Argument has 1 elements
+ varargExample(1, 2, 3) // => Argument has 3 elements
+
+ /*
+ Если функция состоит из одиночного выражения, фигурные скобки могут быть опущены. Тело функции указывается после знака = .
+ */
+ fun odd(x: Int): Boolean = x % 2 == 1
+ println(odd(6)) // => false
+ println(odd(7)) // => true
+
+ // Если возвращаемый тип может быть выведен, то нам не нужно его дополнительно указывать.
+ fun even(x: Int) = x % 2 == 0
+ println(even(6)) // => true
+ println(even(7)) // => false
+
+ // Функции могут брать другие функции в качестве аргументов, а также могут возвращать функции.
+ fun not(f: (Int) -> Boolean): (Int) -> Boolean {
+ return {n -> !f.invoke(n)}
+ }
+ // Именованные функции могут быть определены в качестве аргументов с помощью оператора :: .
+ val notOdd = not(::odd)
+ val notEven = not(::even)
+ // Lambda-выражения могут быть определены в качестве аргументов.
+ val notZero = not {n -> n == 0}
+ /*
+ Если lambda-выражение имеет только один параметр, то ее определение может быть опущено (вместе с ->).
+ Имя этого единственного параметра будет "it".
+ */
+ val notPositive = not {it > 0}
+ for (i in 0..4) {
+ println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}")
+ }
+
+ // Ключевое слово "class" используется для
+ // объявления классов.
+ class ExampleClass(val x: Int) {
+ fun memberFunction(y: Int): Int {
+ return x + y
+ }
+
+ infix fun infixMemberFunction(y: Int): Int {
+ return x * y
+ }
+ }
+ /*
+ Чтобы создать новый экземпляр класса, нужно вызвать конструктор.
+ Обратите внимание, что в Kotlin нет ключевого слова "new".
+ */
+ val fooExampleClass = ExampleClass(7)
+ // Функции-члены могут быть вызваны с использованием точечной нотации.
+ println(fooExampleClass.memberFunction(4)) // => 11
+ /*
+ В случае, если функция была помечена ключевым словом "infix", она может быть вызвана с помощью инфиксной нотации.
+ */
+ println(fooExampleClass infixMemberFunction 4) // => 28
+
+ /*
+ Data-классы - это компактный способ создать классы, которые лишь хранят данные.
+ Методы "hashCode"/"equals" и "toString" генерируютсяч автоматически.
+ */
+ data class DataClassExample (val x: Int, val y: Int, val z: Int)
+ val fooData = DataClassExample(1, 2, 4)
+ println(fooData) // => DataClassExample(x=1, y=2, z=4)
+
+ // Data-классы обладают функцией "copy".
+ val fooCopy = fooData.copy(y = 100)
+ println(fooCopy) // => DataClassExample(x=1, y=100, z=4)
+
+ // Объекты могут быть деструктурированы на множество переменных.
+ val (a, b, c) = fooCopy
+ println("$a $b $c") // => 1 100 4
+
+ // Деструктурирование в цикле "for"
+ for ((a, b, c) in listOf(fooData)) {
+ println("$a $b $c") // => 1 100 4
+ }
+
+ val mapData = mapOf("a" to 1, "b" to 2)
+ // Map.Entry также может быть дествуктурирован
+ for ((key, value) in mapData) {
+ println("$key -> $value")
+ }
+
+ // Функция "with" аналогична оператору "with" в JavaScript.
+ data class MutableDataClassExample (var x: Int, var y: Int, var z: Int)
+ val fooMutableData = MutableDataClassExample(7, 4, 9)
+ with (fooMutableData) {
+ x -= 2
+ y += 2
+ z--
+ }
+ println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8)
+
+ /*
+ Можно создать список с помощью функции "ListOf".
+ Этот список будет неизменяемым, т.е. элементы не могут быть удалены или добавлены в него.
+ */
+ val fooList = listOf("a", "b", "c")
+ println(fooList.size) // => 3
+ println(fooList.first()) // => a
+ println(fooList.last()) // => c
+ // Элементы списка доступны по их индексу в нем.
+ println(fooList[1]) // => b
+
+ // Изменяемый список может быть создан спомощью функции "mutableListOf".
+ val fooMutableList = mutableListOf("a", "b", "c")
+ fooMutableList.add("d")
+ println(fooMutableList.last()) // => d
+ println(fooMutableList.size) // => 4
+
+ // Мы можем создать набор, используя функцию "setOf".
+ val fooSet = setOf("a", "b", "c")
+ println(fooSet.contains("a")) // => true
+ println(fooSet.contains("z")) // => false
+
+ // Мы можем создать отображение (map), используя функцию "mapOf".
+ val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9)
+ // Получить доступ к значениям отображения (map) можно с помощью их ключа.
+ println(fooMap["a"]) // => 8
+
+ /*
+ Последовательности представляют собой коллекции с ленивой оценкой.
+ Мы можем создать последовательность, используя функцию "generateSequence".
+ */
+ val fooSequence = generateSequence(1, { it + 1 })
+ val x = fooSequence.take(10).toList()
+ println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+
+ // Пример использования последовательности для генерации чисел Фибоначчи:
+ fun fibonacciSequence(): Sequence<Long> {
+ var a = 0L
+ var b = 1L
+
+ fun next(): Long {
+ val result = a + b
+ a = b
+ b = result
+ return a
+ }
+
+ return generateSequence(::next)
+ }
+ val y = fibonacciSequence().take(10).toList()
+ println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
+
+ // Kotlin предоставляет функции высшего порядка для работы с коллекциями.
+ val z = (1..9).map {it * 3}
+ .filter {it < 20}
+ .groupBy {it % 2 == 0}
+ .mapKeys {if (it.key) "even" else "odd"}
+ println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]}
+
+ // Цикл "for" может использоваться со всем, что предоставляет итератор.
+ for (c in "hello") {
+ println(c)
+ }
+
+ // Циклы "while" работают также, как и в других языках.
+ var ctr = 0
+ while (ctr < 5) {
+ println(ctr)
+ ctr++
+ }
+ do {
+ println(ctr)
+ ctr++
+ } while (ctr < 10)
+
+ /*
+ "if" может быть использован в качестве выражения, которое возвращает значение.
+ По этой причине в Kotlin тернарный оператор ?: не нужен.
+ */
+ val num = 5
+ val message = if (num % 2 == 0) "even" else "odd"
+ println("$num is $message") // => 5 is odd
+
+ // "when" может быть использован как альтернатива цепочке "if-else if".
+ val i = 10
+ when {
+ i < 7 -> println("first block")
+ fooString.startsWith("hello") -> println("second block")
+ else -> println("else block")
+ }
+
+ // "when" может быть использован с аргументами.
+ when (i) {
+ 0, 21 -> println("0 or 21")
+ in 1..20 -> println("in the range 1 to 20")
+ else -> println("none of the above")
+ }
+
+ // "when" также может быть использовано как функция, возвращающая значение.
+ var result = when (i) {
+ 0, 21 -> "0 or 21"
+ in 1..20 -> "in the range 1 to 20"
+ else -> "none of the above"
+ }
+ println(result)
+
+ /*
+ Мы можем проверить, что объект принадлежит к определенному типу, используя оператор "is".
+ Если объект проходит проверку типа, то он может использоваться как этот тип без явной его передачи.
+ */
+ fun smartCastExample(x: Any) : Boolean {
+ if (x is Boolean) {
+ // x is automatically cast to Boolean
+ return x
+ } else if (x is Int) {
+ // x is automatically cast to Int
+ return x > 0
+ } else if (x is String) {
+ // x is automatically cast to String
+ return x.isNotEmpty()
+ } else {
+ return false
+ }
+ }
+ println(smartCastExample("Hello, world!")) // => true
+ println(smartCastExample("")) // => false
+ println(smartCastExample(5)) // => true
+ println(smartCastExample(0)) // => false
+ println(smartCastExample(true)) // => true
+
+ // Smartcast также работает с блоком "when"
+ fun smartCastWhenExample(x: Any) = when (x) {
+ is Boolean -> x
+ is Int -> x > 0
+ is String -> x.isNotEmpty()
+ else -> false
+ }
+
+ /*
+ Расширения - это способ добавить новый функционал к классу.
+ Это то же самое, что методы расширений в C#.
+ */
+ fun String.remove(c: Char): String {
+ return this.filter {it != c}
+ }
+ println("Hello, world!".remove('l')) // => Heo, word!
+
+ println(EnumExample.A) // => A
+ println(ObjectExample.hello()) // => hello
+}
+
+// Enum-классы схожи с типами enum в Java.
+enum class EnumExample {
+ A, B, C
+}
+
+/*
+Ключевое слово "object" может использоваться для создания одноэлементных объектов.
+Мы не можем его инстанцировать, но можем вызывать его уникальный экземпляр по имени.
+Это похоже на одиночные объекты Scala.
+*/
+object ObjectExample {
+ fun hello(): String {
+ return "hello"
+ }
+}
+
+fun useObject() {
+ ObjectExample.hello()
+ val someRef: Any = ObjectExample // we use objects name just as is
+}
+
+```
+
+### Дальнейшее чтение:
+
+* [Учебные материалы по Kotlin](https://kotlinlang.org/docs/tutorials/)
+* [Попробуй Kotlin в своем браузере](http://try.kotlinlang.org/)
+* [Список ресурсов по языку Kotlin](http://kotlin.link/)
diff --git a/ru-ru/learnvisualbasic-ru.html.markdown b/ru-ru/learnvisualbasic-ru.html.markdown
new file mode 100644
index 00000000..72e1358c
--- /dev/null
+++ b/ru-ru/learnvisualbasic-ru.html.markdown
@@ -0,0 +1,284 @@
+---
+language: Visual Basic
+contributors:
+ - ["Brian Martin", "http://brianmartin.biz"]
+translators:
+ - ["satory-ra", "https://github.com/satory-ra"]
+filename: learnvisualbasic-ru.vb
+lang: ru-ru
+---
+
+```vbnet
+Module Module1
+
+ Sub Main()
+ 'Краткий обзор консольных приложений Visual Basic перед более
+ 'глубоким изучением.
+ 'Апостроф начинает строку комментария.
+ 'Чтобы изучить это руководство в компиляторе Visual Basic,
+ 'я создал систему навигации.
+ 'Эта система будет объяснена при прохождении этого урока.
+ 'Постепенно вы всё поймете.
+ Console.Title = ("Выучи Х за Y минут")
+ Console.WriteLine("НАВИГАЦИЯ") 'Display
+ Console.WriteLine("")
+ Console.ForegroundColor = ConsoleColor.Green
+ Console.WriteLine("1. Вывод данных")
+ Console.WriteLine("2. Ввод данных")
+ Console.WriteLine("3. Расчёт целых чисел")
+ Console.WriteLine("4. Расчёт десятичных дробей")
+ Console.WriteLine("5. Калькулятор")
+ Console.WriteLine("6. Использование циклов Do While")
+ Console.WriteLine("7. Использование циклов For")
+ Console.WriteLine("8. Условные выражения")
+ Console.WriteLine("9. Выберите напиток")
+ Console.WriteLine("50. О приложении")
+ Console.WriteLine("Выберите номер из списка")
+ Dim selection As String = Console.ReadLine
+ '«Case» в операторе Select не является обязательным.
+ 'Например, "Select selection" вместо "Select Case selection"
+ 'также будет работать.
+ Select Case selection
+ Case "1" 'Вывод данных
+ Console.Clear() 'Очищает окно консоли
+ HelloWorldOutput() 'Открывает приватную подпрограмму.
+ Case "2" 'Ввод данных
+ Console.Clear()
+ HelloWorldInput()
+ Case "3" 'Расчёт целых чисел
+ Console.Clear()
+ CalculatingWholeNumbers()
+ Case "4" 'Расчёт десятичных дробей
+ Console.Clear()
+ CalculatingDecimalNumbers()
+ Case "5" 'Калькулятор
+ Console.Clear()
+ WorkingCalculator()
+ Case "6" 'Использование циклов Do While
+ Console.Clear()
+ UsingDoWhileLoops()
+ Case "7" 'Использование циклов For
+ Console.Clear()
+ UsingForLoops()
+ Case "8" 'Условные выражения
+ Console.Clear()
+ ConditionalStatement()
+ Case "9" 'Выражения If/Else
+ Console.Clear()
+ IfElseStatement() 'Выберите напиток
+ Case "50" 'Окно сообщения «О приложении»
+ Console.Clear()
+ Console.Title = ("Выучи Х за Y минут :: О приложении")
+ MsgBox("Это руководство от Брайана Мартина (@BrianMartinn")
+ Console.Clear()
+ Main()
+ Console.ReadLine()
+
+ End Select
+ End Sub
+
+ 'Один - Я использую эти цифры для того, чтобы было проще
+ 'соотносить код с системой навигации.
+
+ 'Мы используем частные подпрограммы для разделения различных
+ 'разделов программы.
+ Private Sub HelloWorldOutput()
+ 'Название консольного приложения
+ Console.Title = "Вывод данных | Выучи Х за Y минут"
+ 'Используйте Console.Write ("") или Console.WriteLine ("")
+ 'для отображения результатов.
+ 'Затем следует Console.Read () или Console.Readline ()
+ 'Console.ReadLine () показывает вывод в консоли.
+ Console.WriteLine("Hello World")
+ Console.ReadLine()
+ End Sub
+
+ 'Два
+ Private Sub HelloWorldInput()
+ Console.Title = "Ввод данных | Выучи Х за Y минут"
+ 'Переменная
+ 'используется для хранения пользовательских данных.
+ 'Объявление переменных начинается с Dim и заканчиваются
+ 'As VariableType (тип переменной).
+
+ 'В этом уроке мы хотим узнать ваше имя и заставить программу
+ 'реагировать на это.
+ Dim username As String
+ 'Мы используем тип «string», так как ваше имя - это текстовая переменная.
+ Console.WriteLine("Привет, как тебя зовут? ") 'Просит ввести имя.
+ username = Console.ReadLine() 'Сохраняет имя в переменной username.
+ Console.WriteLine("Пирвет, " + username) 'Выводит: «Привет, 'имя'»
+ Console.ReadLine() 'Отображает вышеуказанный вывод.
+
+ 'Вышеуказанная программа спросит ваше имя и скажет вам привет.
+ 'Есть и другие типы переменных, такие как целые числа (Integer),
+ 'мы используем Integer для обработки целых чисел.
+ End Sub
+
+ 'Три
+ Private Sub CalculatingWholeNumbers()
+ Console.Title = "Расчёт целых чисел | Выучи Х за Y минут"
+ Console.Write("Первое число: ") 'Введите первое целое число: 1, 2, 50, 104 и т.д.
+ Dim a As Integer = Console.ReadLine()
+ Console.Write("Второе число: ") 'Введите второе целое число.
+ Dim b As Integer = Console.ReadLine()
+ Dim c As Integer = a + b
+ Console.WriteLine(c)
+ Console.ReadLine()
+ 'Приведенная программа сумирует два целых числа
+ End Sub
+
+ 'Четыре
+ Private Sub CalculatingDecimalNumbers()
+ Console.Title = "Расчёт десятичных дробей | Выучи Х за Y минут"
+ 'Мы также должны уметь обрабатывать десятичные дроби.
+ 'Просто измените тип переменной с Integer на Double.
+
+ 'Введите число с плавающей точкой: 1.2, 2.4, 50.1, 104.9 и т.д.
+ Console.Write("Первое число: ")
+ Dim a As Double = Console.ReadLine
+ Console.Write("Второе число: ") 'Введите второе число с плавающей точкой.
+ Dim b As Double = Console.ReadLine
+ Dim c As Double = a + b
+ Console.WriteLine(c)
+ Console.ReadLine()
+ 'Приведенный выше код может сложить две десятичных дроби.
+ End Sub
+
+ 'Пять
+ Private Sub WorkingCalculator()
+ Console.Title = "Калькулятор | Выучи Х за Y минут"
+ 'Но что, если вам нужен калькулятор, который может обрабатывать сложение,
+ 'вычитание, умножение и деление?
+ 'Просто скопируйте и вставьте приведенный код.
+ Console.Write("Первое число: ")
+ Dim a As Double = Console.ReadLine
+ Console.Write("Второе число: ")
+ Dim b As Double = Console.ReadLine
+ Dim c As Double = a + b
+ Dim d As Double = a * b
+ Dim e As Double = a - b
+ Dim f As Double = a / b
+
+ 'С помощью следующего кода мы можем вывести результат сложения,
+ 'вычитания, умножения и деления, рассчитанный выше, на экран.
+ Console.Write(a.ToString() + " + " + b.ToString())
+ 'Мы хотим, чтобы в начале ответа было 3 пробела, для этого
+ 'вы можете использовать метод String.PadLeft (3).
+ Console.WriteLine(" = " + c.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " * " + b.ToString())
+ Console.WriteLine(" = " + d.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " - " + b.ToString())
+ Console.WriteLine(" = " + e.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " / " + b.ToString())
+ Console.WriteLine(" = " + f.ToString.PadLeft(3))
+ Console.ReadLine()
+
+ End Sub
+
+ 'Шесть
+ Private Sub UsingDoWhileLoops()
+ 'Код такой же, как и в предидущей подпрограмме
+ 'На этот раз мы спрашиваем, хочет ли пользователь продолжить (да или нет?)
+ 'Мы будем использовать цикл Do While, потому что не знаем,
+ 'понадобиться ли пользователю калькулятор болше одного раза.
+ Console.Title = "Использование циклов Do While | Выучи Х за Y минут"
+ Dim answer As String
+ 'Мы используем тип переменной "String", так как её значение текст.
+ Do 'Мы начаем программу с
+ Console.Write("Первое число: ")
+ Dim a As Double = Console.ReadLine
+ Console.Write("Второе число: ")
+ Dim b As Double = Console.ReadLine
+ Dim c As Double = a + b
+ Dim d As Double = a * b
+ Dim e As Double = a - b
+ Dim f As Double = a / b
+
+ Console.Write(a.ToString() + " + " + b.ToString())
+ Console.WriteLine(" = " + c.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " * " + b.ToString())
+ Console.WriteLine(" = " + d.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " - " + b.ToString())
+ Console.WriteLine(" = " + e.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " / " + b.ToString())
+ Console.WriteLine(" = " + f.ToString.PadLeft(3))
+ Console.ReadLine()
+ 'Спросите пользователя, хочет ли он продолжить,
+ 'в ответе учитывается регистр букв.
+ Console.Write("Желаете ли вы продолжить? (да / нет)")
+ 'Программа берет значение и записывает в переменную answer.
+ answer = Console.ReadLine()
+ 'Когда пользователь вводит «да», программа переходит к Do и снова запускается.
+ Loop While answer = "yes"
+
+ End Sub
+
+ 'Семь
+ Private Sub UsingForLoops()
+ 'Иногда программу нужно запускать только один раз.
+ 'В этой программе мы осуществим обратный отсчет от 10.
+
+ Console.Title = "Использование циклов For | Выучи Х за Y минут"
+ 'Объявите переменные и Step (размер шага, то есть скорость уменьшения,
+ 'например, -1, -2, -3 и т.д.).
+ For i As Integer = 10 To 0 Step -1
+ Console.WriteLine(i.ToString) 'Показывает значение счетчика.
+ Next i 'Рассчитать новое значение i.
+ Console.WriteLine("Поехали")
+ Console.ReadLine()
+ End Sub
+
+ 'Восемь
+ Private Sub ConditionalStatement()
+ Console.Title = "Условные выражения | Выучи Х за Y минут"
+ Dim userName As String
+ Console.WriteLine("Привет, как тебя зовут? ") 'Спросите имя пользователя.
+ userName = Console.ReadLine() 'Записать имя в переменную userName.
+ If userName = "Адам" Then
+ Console.WriteLine("Привет, Адам")
+ Console.WriteLine("Спасибо за создание этого полезного сайта")
+ Console.ReadLine()
+ Else
+ Console.WriteLine("Привет " + userName)
+ Console.WriteLine("Вы заглянули на сайт www.learnxinyminutes.com")
+ Console.ReadLine() 'Программа останавливается и выводит вышеуказанный текст.
+ End If
+ End Sub
+
+ 'Девять
+ Private Sub IfElseStatement()
+ Console.Title = "Выражения If/Else | Выучи Х за Y минут"
+ 'Иногда важно рассмотреть более двух альтернатив.
+ 'Иногда некоторые из них лучше других.
+ 'Когда это произойдет, нам потребуется более одного утверждения «if» (если).
+ 'Оператор «if» подобен торговому автомату.
+ 'В котором пользователь пишет код (A1, A2, A3 и т.д.), чтобы выбрать элементы.
+ 'Все варианты могут быть объединены в одном утверждении «if».
+
+ Dim selection As String 'Объявить переменную для выбора
+ Console.WriteLine("Пожалуйста, выберите продукт из нашего прекрасного торгового автомата.")
+ Console.WriteLine("A1. для 7Up")
+ Console.WriteLine("A2. для Fanta")
+ Console.WriteLine("A3. для Dr. Pepper")
+ Console.WriteLine("A4. для Diet Coke")
+
+ selection = Console.ReadLine() 'Сохранить выбор пользователя
+ If selection = "A1" Then
+ Console.WriteLine("7up")
+ ElseIf selection = "A2" Then
+ Console.WriteLine("Fanta")
+ ElseIf selection = "A3" Then
+ Console.WriteLine("Dr. Pepper")
+ ElseIf selection = "A4" Then
+ Console.WriteLine("Diet Coke")
+ Else
+ Console.WriteLine("Извините, у меня нет " + selection)
+ End If
+ Console.ReadLine()
+
+ End Sub
+
+End Module
+
+```
diff --git a/ru-ru/linker-ru.html.markdown b/ru-ru/linker-ru.html.markdown
new file mode 100644
index 00000000..7df29c23
--- /dev/null
+++ b/ru-ru/linker-ru.html.markdown
@@ -0,0 +1,203 @@
+---
+category: tool
+tool: linker
+contributors:
+ - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
+translators:
+ - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
+lang: ru-ru
+---
+
+# Основные понятия и определения
+**Счетчик позиций** - у компоновщика есть специальная переменная
+"." (точка) всегда содержит текущую позицию вывода.
+
+# Функции
+**ADDR(section)** - возвращает абсолютный адрес указанной секции. Однако
+данная секция должна быть определенна до использования функции ADDR.
+
+**ALIGN(exp)** - возвращает значение счетчика позиций, выравненное на границу
+следующего за exp выражения.
+
+**SIZEOF(section)** - возвращает размер секции в байтах.
+
+**FILL(param)** - определяет образец заполнения для текущей секции. Все
+остальные неуказанные регионы внутри секции заполняются значением указанными
+в аргументе функции.
+
+**KEEP(param)** - используется чтобы помечать param как неустранимый.
+
+**ENTRY(func)** - определяет функцию, которая будет являться точкой входа
+в программу.
+
+```bash
+# Определяем точку входа в программу
+ENTRY(Reset_Handler)
+
+# Определяем перемнную которая содержит адрес вершины стека
+_estack = 0x20020000;
+# Определяем перемнную которая содержит значение размера кучи
+_Min_Heap_Size = 0x200;
+# Определяем перемнную которая содержит значение размера стека
+_Min_Stack_Size = 0x400;
+
+# Описание карты памяти доступной для данного процессора
+# MEMORY
+# {
+# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР
+# }
+# В нашем примере контроллер содержит три области памяти:
+# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт;
+# CCMRAM - начинается с адреса 0x10000000и занимает 64 Кбайт;
+# FLASH - начинается с адреса 0x8000000 занимает 1024 Кбайт;
+# Причем RAM память доступка для чтения, записи и исполнения.
+# CCMRAM память доступна только на чтение и запись.
+# FLASH память доступна на чтение и исполнение.
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+ CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
+ FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
+}
+
+# Описываем выходные секции
+SECTIONS
+{
+ # Первая секция содержит таблицу векторов прерываний
+ .isr_vector :
+ {
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
+ # входных разделов. И если есть разделы, которые сборщик муссора не должен трогать,
+ # то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
+ # volatile).
+ # Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
+ # обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛА(ИМЯ_РАЗДЕЛА))
+ KEEP(*(.isr_vector))
+
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Выражение ">ОБЛАСТЬ_ПАМЯТИ" указывает в какую именно область памяти будет помещенна
+ # данная секция. В нашем слущае секция .isr_vector будет размещена во FLASH памяти.
+ } >FLASH
+
+# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
+# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале
+# FLASH памяти микроконтроллера.
+
+ # Вторая секция содержит код программы.
+ .text :
+ {
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Указываем, что в данной секции будут хранится области .text всех
+ # объектных файлов
+ *(.text)
+ *(.text*)
+
+ # Защищаем от сборщика мусора секции .init и .fini
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая
+ # может быть доступна в исходном тексте программы через объявление
+ # volaile unsigned int extern _etext;
+ _etext = .;
+ } >FLASH
+
+# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт,
+# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные
+от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH
+памяти микроконтроллера сразу за таблицей векторов.
+Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они
+объявлены в скрипте.
+
+ # Третья секция содержит константные данные.
+ .rodata :
+ {
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Указываем, что в данной секции будут хранится области .rodataвсех
+ # объектных файлов
+ *(.rodata)
+ *(.rodata*)
+
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+ } >FLASH
+
+ # Сохраняем в переменной _sidata абсолютный адрес секции .data
+ _sidata = LOADADDR(.data);
+
+ # Четвертая секция содержит инициализированные переменные.
+ .data :
+ {
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Сохраняем в переменной _sdata адрес текущей позиции (начала секции)
+ _sdata = .;
+
+ # Указываем, что в данной секции будут хранится области .data всех
+ # объектных файлов
+ *(.data)
+ *(.data*)
+
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Сохраняем в переменной _sdata адрес текущей позиции (конец секции)
+ _edata = .;
+
+ # Функция AT указывает на то, что данный сектор хранится в одной области памяти
+ # (в нашем случае FLASH), а исполняться будет из другой обасти памяти (в нашем случае RAM).
+ # Есть два типа адрессов:
+ # * VMA (Virtual memory address) - это run-time адрес по которому уомпилятор ожидает
+ # видеть данные.
+ # * LMA (Load memory address) - это адрес по которому линкер хранит данные.
+
+ #Startup должен код скопировать секцию .data из адрессов LMA в адресса VMA.
+
+ } >RAM AT> FLASH
+
+ # Пятая секция содержит инициализированные нулем переменные.
+ .bss :
+ {
+ # Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции)
+ _sbss = .;
+ __bss_start__ = _sbss;
+
+ # Указываем, что в данной секции будут хранится области .bss всех
+ # объектных файлов
+ *(.bss)
+ *(.bss*)
+
+ # Выравниваем текущую позицию на границу 4-х байт.
+ . = ALIGN(4);
+
+ # Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции)
+ _ebss = .;
+ __bss_end__ = _ebss;
+ } >RAM
+
+ # Шестая секция содержит кучу и стек. Размещается в самом конце RAM.
+ ._user_heap_stack :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(4);
+ } >RAM
+}
+```
+
diff --git a/ru-ru/markdown-ru.html.markdown b/ru-ru/markdown-ru.html.markdown
index ff7a0cc3..579a9a20 100644
--- a/ru-ru/markdown-ru.html.markdown
+++ b/ru-ru/markdown-ru.html.markdown
@@ -36,13 +36,14 @@ lang: ru-ru
Markdown является надмножеством HTML, поэтому любой HTML-файл является
корректным документом Markdown.
- ```markdown
+ ```md
<!-- Это позволяет использовать напрямую
любые элементы HTML-разметки, такие, например, как этот комментарий.
Встроенные в документ HTML-элементы не затрагиваются парсером Markdown
и попадают в итоговый HTML без изменений. Однако следует понимать,
что эта же особенность не позволяет использовать разметку Markdown внутри
HTML-элементов -->
+```
## Заголовки
@@ -50,7 +51,7 @@ HTML-элементы от <h1> до <h6> размечаются очень пр
текст, который должен стать заголовком, предваряется
соответствующим количеством символов "#":
-```markdown
+```md
# Это заголовок h1
## Это заголовок h2
### Это заголовок h3
@@ -60,7 +61,7 @@ HTML-элементы от <h1> до <h6> размечаются очень пр
```
Markdown позволяет размечать заголовки <h1> и <h2> ещё одним способом:
-```markdown
+```md
Это заголовок h1
================
@@ -72,7 +73,7 @@ Markdown позволяет размечать заголовки <h1> и <h2>
Текст легко сделать полужирным и/или курсивным:
-```markdown
+```md
*Этот текст будет выведен курсивом.*
_Так же, как этот._
@@ -87,7 +88,7 @@ __И этот тоже.__
В Github Flavored Markdown, стандарте, который используется в Github,
текст также можно сделать зачёркнутым:
-```markdown
+```md
~~Зачёркнутый текст.~~
```
@@ -96,7 +97,7 @@ __И этот тоже.__
Абзацами являются любые строки, следующие друг за другом.
Разделяются же абзацы одной или несколькими пустыми строками:
-```markdown
+```md
Это абзац. Я печатаю в абзаце, разве это не прикольно?
А тут уже абзац №2.
@@ -108,7 +109,7 @@ __И этот тоже.__
Для вставки принудительных переносов можно завершить абзац двумя дополнительными пробелами:
-```markdown
+```md
Эта строка завершается двумя пробелами (выделите, чтобы увидеть!).
Над этой строкой есть <br />!
@@ -116,7 +117,7 @@ __И этот тоже.__
Цитаты размечаются с помощью символа «>»:
-```markdown
+```md
> Это цитата. В цитатах можно
> принудительно переносить строки, вставляя «>» в начало каждой следующей строки. А можно просто оставлять их достаточно длинными, и такие длинные строки будут перенесены автоматически.
> Разницы между этими двумя подходами к переносу строк нет, коль скоро
@@ -133,7 +134,7 @@ __И этот тоже.__
одного из символов «*», «+» или «-»:
(символ должен быть одним и тем же для всех элементов)
-```markdown
+```md
* Список,
* Размеченный
* Звёздочками
@@ -154,7 +155,7 @@ __И этот тоже.__
В нумерованных списках каждая строка начинается
с числа и точки вслед за ним:
-```markdown
+```md
1. Первый элемент
2. Второй элемент
3. Третий элемент
@@ -164,7 +165,7 @@ __И этот тоже.__
любое число в начале каждого элемента, и парсер пронумерует элементы сам!
Правда, злоупотреблять этим не стоит :)
-```markdown
+```md
1. Первый элемент
1. Второй элемент
1. Третий элемент
@@ -173,7 +174,7 @@ __И этот тоже.__
Списки могут быть вложенными:
-```markdown
+```md
1. Введение
2. Начало работы
3. Примеры использования
@@ -184,7 +185,7 @@ __И этот тоже.__
Можно даже делать списки задач. Блок ниже создаёт HTML-флажки.
-```markdown
+```md
Для отметки флажка используйте «x»
- [ ] Первая задача
- [ ] Вторая задача
@@ -197,7 +198,7 @@ __И этот тоже.__
Фрагменты исходного кода (обычно отмечаемые тегом `<code>`) выделяются просто:
каждая строка блока должна иметь отступ в четыре пробела либо в один символ табуляции.
-```markdown
+```md
Это код,
причём многострочный
```
@@ -205,7 +206,7 @@ __И этот тоже.__
Вы также можете делать дополнительные отступы, добавляя символы табуляции
или по четыре пробела:
-```markdown
+```md
my_array.each do |item|
puts item
end
@@ -215,7 +216,7 @@ __И этот тоже.__
не выделяя код в блок. Для этого фрагменты кода нужно обрамлять
символами «`»:
-```markdown
+```md
Ваня даже не знал, что делает функция `go_to()`!
```
@@ -237,7 +238,7 @@ end
Разделители (`<hr>`) добавляются вставкой строки из трёх и более
(одинаковых) символов «*» или «-», с пробелами или без них:
-```markdown
+```md
***
---
- - -
@@ -251,18 +252,18 @@ end
текст ссылки, заключив его в квадратные скобки,
и сразу после — URL-адрес, заключенный в круглые
-```markdown
+```md
[Ссылка!](http://test.com/)
```
Также для ссылки можно указать всплывающую подсказку (`title`), используя
кавычки внутри круглых скобок:
-```markdown
+```md
[Ссылка!](http://test.com/ "Ссылка на Test.com")
```
Относительные пути тоже возможны:
-```markdown
+```md
[Перейти к музыке](/music/).
```
@@ -290,7 +291,7 @@ Markdown также позволяет размечать ссылку в вид
Разметка изображений очень похожа на разметку ссылок.
Нужно всего лишь добавить перед ссылкой восклицательный знак!
-```markdown
+```md
![Альтернативный текст для изображения](http://imgur.com/myimage.jpg "Подсказка")
```
Изображения тоже могут быть оформлены, как сноски.
@@ -301,20 +302,20 @@ Markdown также позволяет размечать ссылку в вид
## Разное
### Автоссылки
-```markdown
+```md
Ссылка вида <http://testwebsite.com/> эквивалентна
[http://testwebsite.com/](http://testwebsite.com/)
```
### Автоссылки для адресов электронной почты
-```markdown
+```md
<foo@bar.com>
```
### Экранирование символов
-```markdown
+```md
Я хочу напечатать *текст, заключённый в звёздочки*, но я не хочу,
чтобы он был курсивным. Тогда я делаю так:
\*Текст, заключённый в звёздочки\*
@@ -324,7 +325,7 @@ Markdown также позволяет размечать ссылку в вид
В Github Flavored Markdown для представления клавиш на клавиатуре
вы можете использовать тег `<kbd>`.
-```markdown
+```md
Ваш компьютер завис? Попробуйте нажать
<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd>
```
@@ -334,7 +335,7 @@ Markdown также позволяет размечать ссылку в вид
да и синтаксис имеют не слишком удобный.
Но если очень нужно, размечайте таблицы так:
-```markdown
+```md
| Столбец 1 | Столбец 2 | Столбец 3 |
| :----------- | :----------: | -----------: |
| Выравнивание | Выравнивание | Выравнивание |
@@ -342,7 +343,7 @@ Markdown также позволяет размечать ссылку в вид
```
Или более компактно
-```markdown
+```md
Столбец 1|Столбец 2|Столбец 3
:--|:-:|--:
Выглядит|это|страшновато...
diff --git a/ru-ru/nim-ru.html.markdown b/ru-ru/nim-ru.html.markdown
new file mode 100644
index 00000000..0e08f1bf
--- /dev/null
+++ b/ru-ru/nim-ru.html.markdown
@@ -0,0 +1,285 @@
+---
+language: Nim
+filename: learnNim-ru.nim
+contributors:
+ - ["Jason J. Ayala P.", "http://JasonAyala.com"]
+ - ["Dennis Felsing", "http://felsin9.de/nnis/"]
+translators:
+ - ["Nomadic", "https://github.com/n0madic"]
+ - ["dvska", "https://github.com/dvska"]
+lang: ru-ru
+---
+
+Nim (ранее известный, как Nimrod) — язык программирования со статической
+типизацией, поддерживающий процедурный, объектно-ориентированный,
+функциональный и обобщённый стили программирования.
+
+Nim эффективный, выразительный и элегантный.
+
+```nim
+var # Объявление (и присваивание) переменных,
+ буква: char = 'n' # с указанием типа или без
+ язык = "N" & "im"
+ nLength : int = len(язык)
+ boat: float
+ правда: bool = false
+
+let # Используйте let *сразу* для объявления и связывания переменных.
+ ноги = 400 # ноги неизменяемый.
+ руки = 2_000 # Символ _ игнорируется и удобен для длинных чисел.
+ почтиПи = 3.15
+
+const # Константы вычисляются во время компиляции. Это обеспечивает
+ debug = true # производительность и полезно в выражениях этапа компиляции.
+ компилироватьПлохойКод = false
+
+when компилироватьПлохойКод: # `when` это `if` этапа компиляции.
+ ноги = ноги + 1 # Эта ошибка никогда не будет скомпилирована.
+ const ввод = readline(stdin) # Значения констант должны быть известны во
+ # время компиляции.
+
+discard 1 > 2 # Примечание. Компилятор будет жаловаться, если результат
+ # выражения не используется. `discard` обходит это.
+
+discard """
+Это может использоваться как многострочный комментарий.
+Или для не поддающегося синтаксическому анализу, сломанного кода
+"""
+
+#
+# Структуры данных
+#
+
+# Кортежи
+
+var
+ дитя: tuple[имя: string, возраст: int] # Кортежи определяют *как* имя поля
+ сегодня: tuple[солнце: string, температура: float] # так *и* порядок полей.
+
+дитя = (имя: "Rudiger", возраст: 2) # Присвоить все сразу литералом ()
+сегодня.солнце = "Пасмурно" # или отдельно по полям.
+сегодня.температура = 20.1
+
+# Последовательности
+
+var
+ напитки: seq[string]
+
+напитки = @["Вода", "Сок", "Какао"] # @[V1,..,Vn] является литералом
+ # последовательности
+
+напитки.add("Молоко")
+
+if "Молоко" in напитки:
+ echo "У нас тут Молоко и ещё", напитки.len - 1, " напиток(ов)"
+
+let мойНапиток = напитки[2]
+
+#
+# Определение типов
+#
+
+# Определение собственных типов позволяет компилятору работать на вас.
+# Это то, что делает статическую типизацию мощной и полезной.
+
+type
+ Имя = string # Псевдоним типа дает вам новый тип, который равнозначен
+ Возраст = int # старому типу, но более нагляден.
+ Человек = tuple[имя: Имя, возраст: Возраст] # Определение структур данных.
+ АльтернативныйСинтаксис = tuple
+ fieldOne: string
+ secondField: int
+
+var
+ джон: Человек = (имя: "John B.", возраст: 17)
+ новыйВозраст: int = 18 # Было бы лучше использовать Возраст, чем int
+
+джон.возраст = новыйВозраст # Но это все же работает, потому что int и Возраст синонимы.
+
+type
+ Нал = distinct int # `distinct` делает новый тип несовместимым с его
+ Описание = distinct string # базовым типом.
+
+var
+ money: Нал = 100.Нал # `.Нал` преобразует int в наш тип
+ описание: Описание = "Interesting".Описание
+
+when компилироватьПлохойКод:
+ джон.возраст = money # Error! возраст is of type int and money is Нал
+ джон.имя = описание # Компилятор говорит: "Нельзя!"
+
+#
+# Дополнительные типы и структуры данных
+#
+
+# Перечисления позволяют типу иметь одно из ограниченного числа значений
+
+type
+ Цвет = enum цКрасный, цГолубой, цЗеленый
+ Направление = enum # Альтернативный формат
+ нСевер
+ нЗапад
+ нВосток
+ нЮг
+var
+ напр = нСевер # `напр` имеет тип Направление, со значением `нСевер`
+ точка = цЗеленый # `точка` имеет тип Цвет, со значением `цЗеленый`
+
+discard нСевер > нВосток # Перечисления обычно являются "порядковыми" типами
+
+# Поддиапазоны определяют ограниченный допустимый диапазон
+
+type
+ Кости = range[1..20] # 🎲 Допустимым значением являются только int от 1 до 20
+var
+ мой_бросок: Кости = 13
+
+when компилироватьПлохойКод:
+ мой_бросок = 23 # Error!
+
+# Массивы
+
+type
+ СчетчикБросков = array[Кости, int] # Массивы фиксированной длины и
+ ИменаНаправлений = array[Направление, string] # индексируются любым порядковым типом.
+ Истины = array[42..44, bool]
+var
+ счетчик: СчетчикБросков
+ направления: ИменаНаправлений
+ возможны: Истины
+
+возможны = [false, false, false] # Массивы создаются литералом [V1,..,Vn]
+возможны[42] = true
+
+направления[нСевер] = "ОО. Великий белый Север!"
+направления[нЗапад] = "Нет, не иди туда."
+
+мой_бросок = 13
+счетчик[мой_бросок] += 1
+счетчик[мой_бросок] += 1
+
+var ещеМассив = ["Идекс по умолчанию", "начинается с", "0"]
+
+# Доступны другие структуры данных, в том числе таблицы, множества,
+# списки, очереди и crit-bit деревья.
+# http://nim-lang.org/docs/lib.html#collections-and-algorithms (EN)
+
+#
+# IO и поток управления выполнением
+#
+
+# `case`, `readLine()`
+
+echo "Читали какие-нибудь хорошие книги в последнее время?"
+
+case readLine(stdin)
+of "нет", "Нет":
+ echo "Пойдите в свою местную библиотеку."
+of "да", "Да":
+ echo "Тогда продолжим"
+else:
+ echo "Здорово!"
+
+# `while`, `if`, `continue`, `break`
+
+import strutils as str # http://nim-lang.org/docs/strutils.html (EN)
+echo "Я загадало число между 41 и 43. Отгадай!"
+let число: int = 42
+var
+ ввод_догадка: string
+ догадка: int
+
+while догадка != число:
+ ввод_догадка = readLine(stdin)
+
+ if ввод_догадка == "": continue # Пропустить эту итерацию
+
+ догадка = str.parseInt(ввод_догадка)
+
+ if догадка == 1001:
+ echo("AAAAAAGGG!")
+ break
+ elif догадка > число:
+ echo("Неа. Слишком большое.")
+ elif догадка < число:
+ echo(догадка, " это слишком мало")
+ else:
+ echo("Точнооооо!")
+
+#
+# Итерации (циклы)
+#
+
+for i, элем in ["Да", "Нет", "Может быть"]: # Или просто `for элем in`
+ echo(элем, " по индексу: ", i)
+
+for ключ, значение in items(@[(человек: "You", сила: 100), (человек: "Me", сила: 9000)]):
+ echo значение
+
+let мояСтрока = """
+<пример>
+`строки` для
+тренировки
+""" # Многострочная "сырая" строка
+
+for строка in splitLines(мояСтрока):
+ echo(строка)
+
+for i, симв in мояСтрока: # Индекс и символ. Или `for j in` только для символов
+ if i mod 2 == 0: continue # Компактная форма `if`
+ elif симв == 'X': break
+ else: echo(симв)
+
+#
+# Процедуры
+#
+
+type Ответ = enum оДа, оНет
+
+proc спрос(вопрос: string): Ответ =
+ echo(вопрос, " (д/н)")
+ while true:
+ case readLine(stdin)
+ of "д", "Д", "да", "Да":
+ return Ответ.оДа # Перечисления могут быть квалифицированы
+ of "н", "Н", "нет", "Нет":
+ return Ответ.оНет
+ else: echo("Поточнее, да или нет")
+
+proc добавьСахар(количество: int = 2) = # Значение по умолчанию 2, ничего не возвращает
+ assert(количество > 0 and количество < 9000, "Диабет ☠")
+ for a in 1..количество:
+ echo(a, " кубик...")
+
+case спрос("Сахарку?")
+of оДа:
+ добавьСахар(3)
+of оНет:
+ echo "Ну немнооожко!"
+ добавьСахар()
+# Здесь нет необходимости в `else`. Возможны только `да` и `нет`.
+
+#
+# FFI (интерфейс внешних функций)
+#
+
+# Так как Nim компилируется в C, то FFI делается очень просто:
+
+proc strcmp(a, b: cstring): cint {.importc: "strcmp", nodecl.}
+
+let cmp = strcmp("C?", "Легко!")
+```
+
+Кроме того, Nim выделяется среди себе подобных метапрограммированием,
+производительностью, функциями этапа компиляции.
+
+## Дальнейшее чтение (EN)
+
+* [Домашняя страница](http://nim-lang.org)
+* [Скачать](http://nim-lang.org/download.html)
+* [Сообщество](http://nim-lang.org/community.html)
+* [FAQ](http://nim-lang.org/question.html)
+* [Документация](http://nim-lang.org/documentation.html)
+* [Руководство](http://nim-lang.org/docs/manual.html)
+* [Стандартная библиотека](http://nim-lang.org/docs/lib.html)
+* [Rosetta Code](http://rosettacode.org/wiki/Category:Nim)
diff --git a/ru-ru/objective-c-ru.html.markdown b/ru-ru/objective-c-ru.html.markdown
index d60db1d8..3baa15f8 100644
--- a/ru-ru/objective-c-ru.html.markdown
+++ b/ru-ru/objective-c-ru.html.markdown
@@ -781,7 +781,7 @@ MyClass *newVar = [classVar retain]; // Если classVar освободится
// автоматический подсчет ссылок (ARC).
// ARC - это особенность компилятора, который помещает "retain", "release"
// и "autorelease" автоматически за вас тогда, когда используется ARC,
-// вам не нужно больше обращаться к "retain", "relase" или "autorelease"
+// вам не нужно больше обращаться к "retain", "release" или "autorelease"
MyClass *arcMyClass = [[MyClass alloc] init];
// ... код, использующий объект arcMyClass
// Без ARC, вам нужно было бы вызвать: [arcMyClass release] после того, как вы
diff --git a/ru-ru/pascal-ru.html.markdown b/ru-ru/pascal-ru.html.markdown
new file mode 100644
index 00000000..5ea856bc
--- /dev/null
+++ b/ru-ru/pascal-ru.html.markdown
@@ -0,0 +1,217 @@
+---
+language: Pascal
+filename: learnpascal-ru.pas
+contributors:
+ - ["Ganesha Danu", "http://github.com/blinfoldking"]
+ - ["Keith Miyake", "https://github.com/kaymmm"]
+translators:
+ - ["Anton 'Dart' Nikolaev", "https://github.com/dartfnm"]
+lang: ru-ru
+---
+
+
+>Pascal - это процедурный язык программирования, который Никлаус Вирт разработал в 1968–69 годах и опубликовал в 1970 году как небольшой эффективный язык, предназначенный для поощрения хороших методов программирования с использованием структурированного программирования и структурирования данных. Он назван в честь французского математика, философа и физика Блеза Паскаля.
+>
+>source : [wikipedia](https://ru.wikipedia.org/wiki/Паскаль_(язык_программирования)))
+
+
+
+Для компиляции и запуска программы на языке Паскаль вы можете использовать бесплатный компилятор FreePascal. [Скачать здесь](https://www.freepascal.org/)
+
+Либо современный бесплатный компилятор Паскаля нового поколения под платформу .Net [PascalABC.NET](http://pascalabc.net)
+
+```pascal
+// это комментарий
+{
+ а вот это:
+ - комментарий на несколько строк
+}
+
+//объявляем имя программы
+program learn_pascal; //<-- не забываем ставить точку с запятой (;)
+
+const
+ {
+ это секция в которой вы должны объявлять константы
+ }
+type
+ {
+ здесь вы можете объявлять собственные типы данных
+ }
+var
+ {
+ секция для объявления переменных
+ }
+
+begin //начало основной программы
+ {
+ тело вашей программы
+ }
+end. // В конце основной программы обязательно должна стоять точка "."
+```
+
+```pascal
+//объявление переменных
+//вы можете сделать так
+var a:integer;
+var b:integer;
+//или так
+var
+ a : integer;
+ b : integer;
+//или даже так
+var a,b : integer;
+```
+
+```pascal
+program Learn_More;
+
+// Познакомимся с типами данных и с их операциями
+const
+ PI = 3.141592654;
+ GNU = 'GNU''s Not Unix';
+ // имена константам принято давать ЗАГЛАВНЫМИ_БУКВАМИ (в верхнем регистре)
+ // их значения фиксированны т.е никогда не меняются во время выполнения программы
+ // содержат любой стандартный тип данных (integer, real, boolean, char, string)
+
+type
+ ch_array : array [0..255] of char;
+ // массивы - это составной тип данных
+ // мы указываем индекс первого и последнего элемента массива ([0..255])
+ // здесь мы объявили новый тип данных содержащий 255 символов 'char'
+ // (по сути, это просто строка - string[256])
+
+ md_array : array of array of integer;
+ // массив в массиве - по сути является двумерным массивом
+ // можно задать массив нулевой (0) длины, а потом динамически расширить его
+ // это двумерный массив целых чисел
+
+//Объявление переменных
+var
+ int, c, d : integer;
+ // три переменные, которые содержат целые числа
+ // Тип "integer" это 16-битное число в диапазоне [-32,768..32,767]
+ r : real;
+ // переменная типа "real" принимает вещественные (дробные) значения
+ // в диапазоне [3.4E-38..3.4E38]
+ bool : boolean;
+ // переменная логического типа, принимающая булевы-значения: True/False (Правда/Ложь)
+ ch : char;
+ // эта переменная содержит значение кода одного символа
+ // тип 'char' это 8-битное число (1 байт), так что никакого Юникода
+ str : string;
+ // это переменная составного типа, являющееся строкой
+ // по сути, строка это массив в 255 символов длиною, по умолчанию
+
+ s : string[50];
+ // эта строка может содержать максимум 50 символов
+ // вы можете сами указать длину строки, чтобы минимизировать использование памяти
+ my_str: ch_array;
+ // вы можете объявлять переменные собственных типов
+ my_2d : md_array;
+ // динамически расширяемые массивы требуют указания длины перед их использованием.
+
+ // дополнительные целочисленные типы данных
+ b : byte; // диапазон [0..255]
+ shi : shortint; // диапазон [-128..127]
+ smi : smallint; // диапазон [-32,768..32,767] (стандартный Integer)
+ w : word; // диапазон [0..65,535]
+ li : longint; // диапазон [-2,147,483,648..2,147,483,647]
+ lw : longword; // диапазон [0..4,294,967,295]
+ c : cardinal; // тоже что и longword
+ i64 : int64; // диапазон [-9223372036854775808..9223372036854775807]
+ qw : qword; // диапазон [0..18,446,744,073,709,551,615]
+
+ // дополнительные вещественные типы данных (дробные)
+ rr : real; // диапазон зависит от платформы (т.е. 8-бит, 16-бит и т.д.)
+ rs : single; // диапазон [1.5E-45..3.4E38]
+ rd : double; // диапазон [5.0E-324 .. 1.7E308]
+ re : extended; // диапазон [1.9E-4932..1.1E4932]
+ rc : comp; // диапазон [-2E64+1 .. 2E63-1]
+
+Begin
+ int := 1; // так мы присваиваем значение переменной
+ r := 3.14;
+ ch := 'a';
+ str := 'apple';
+ bool := true;
+ // Паскаль не чувствителен к регистру
+
+ // арифметические операции
+ int := 1 + 1; // int = 2; заменяет предыдущее значение
+ int := int + 1; // int = 2 + 1 = 3;
+ int := 4 div 2; //int = 2; 'div' операция деления, с отбрасыванием дробной части
+ int := 3 div 2; //int = 1;
+ int := 1 div 2; //int = 0;
+
+ bool := true or false; // bool = true
+ bool := false and true; // bool = false
+ bool := true xor true; // bool = false
+
+ r := 3 / 2; // деления вещественных чисел с дробной частью
+ r := int; // вещественной переменной можно присвоить целочисленное значение, но не наоборот
+
+ my_str[0] := 'a'; // для доступа к элементу массива нужно указать его индекс в квадратных скобках ([0])
+
+ c := str[1]; // первая буква во всех Строках находится по индексу [1]
+ str := 'hello' + 'world'; //объединяем 2 строки в одну
+
+ SetLength(my_2d,10,10); // инициализируем динамически расширяемый массив
+ // задаём размер 2х-мерного массива 10×10
+
+ // первый элемент массива лежит в индексе [0], последний [длина_массива-1]
+ for c := 0 to 9 do
+ for d := 0 to 9 do // переменные для счетчиков циклов должны быть объявлены
+ my_2d[c,d] := c * d;
+ // обращаться к многомерным массивам нужно с помощью одного набора скобок
+
+End.
+```
+
+```pascal
+program Functional_Programming;
+
+Var
+ i, dummy : integer;
+
+function factorial_recursion(const a: integer) : integer;
+{ Функция расчёта Факториала целочисленного параметра 'a', рекурсивно. Возвращает целое значение }
+
+// Мы можем объявлять локальные переменные внутри своей функции:
+// Var
+// local_a : integer;
+
+Begin
+ If a >= 1 Then
+ factorial_recursion := a * factorial_recursion(a-1)
+ // возвращаем результат, присваивая найденное значение переменной с тем же именем, как у функции
+ Else
+ factorial_recursion := 1;
+End; // Для завершения функции, используется символ ";" после оператора "End;"
+
+
+
+procedure get_integer( var i : integer; dummy : integer );
+{ Эта процедура ждёт от пользователя ввода целого числа и возвращает его значение через параметр i.
+ Если параметр функции начинается с 'var', это означает, что его значение было передано, по ссылке, то есть, оно может использоваться не только как входное значение, но и для возвращения дополнительных результатов работы функции.
+ Параметры функции (без 'var'), (такие как "dummy" (пустышка)), передаются по значению, и по сути являются - локальными переменными, таким образом изменения, внесенные внутри функции/процедуры, не влияют на значение переменной за её пределами.
+}
+Begin // начало процедуры
+ write('Введите целое число: ');
+ readln(i); // число, введённое пользователем, сохранится в переменной i
+ // и её значение будет доступно вызывающей подпрограмме
+
+ dummy := 4; // значение 'dummy' не будет влиять на значения переменной вне процедуры
+End; // конец процедуры
+
+Begin // главный блок программы
+ dummy := 3;
+ get_integer(i, dummy); // вызываем процедуру получения числа от пользователя
+ writeln(i, '! = ', factorial_recursion(i)); // ввыводим значение факториала от i
+
+ writeln('dummy = ', dummy);
+ // всегда выводит "3", поскольку фиктивная переменная не изменяется.
+End. // конец программы
+
+```
+
diff --git a/ru-ru/perl-ru.html.markdown b/ru-ru/perl-ru.html.markdown
index a907ba41..a9bb683b 100644
--- a/ru-ru/perl-ru.html.markdown
+++ b/ru-ru/perl-ru.html.markdown
@@ -9,12 +9,12 @@ translators:
lang: ru-ru
---
-Perl 5 -- высокоуровневый мощный язык с 25-летней историей.
-Особенно хорош для обработки разнообразных текстовых данных.
+Perl -- высокоуровневый мощный язык с 25-летней историей.
+Особенно хорош для обработки разнообразных текстовых данных.
-Perl 5 работает более чем на 100 платформах, от портативных устройств
-до мейнфреймов, и подходит как для быстрого прототипирования,
-так и для крупных проектов.
+Perl работает более чем на 100 платформах, от портативных устройств
+до мейнфреймов, и подходит как для быстрого прототипирования,
+так и для крупных проектов.
```perl
# Комментарии начинаются с символа решетки.
@@ -23,8 +23,8 @@ Perl 5 работает более чем на 100 платформах, от п
#### Типы переменных в Perl
# Скалярные переменные начинаются с знака доллара $.
-# Имя переменной состоит из букв, цифр и знаков подчеркивания,
-# начиная с буквы или подчеркивания.
+# Имя переменной состоит из букв, цифр и знаков подчеркивания,
+# начиная с буквы или подчеркивания.
### В Perl три основных типа переменных: скаляры, массивы, хеши.
@@ -55,7 +55,7 @@ my %fruit_color = (
banana => "yellow",
);
-# Важно: вставка и поиск в хеше выполняются за константное время,
+# Важно: вставка и поиск в хеше выполняются за константное время,
# независимо от его размера.
# Скаляры, массивы и хеши подробно описаны в разделе perldata
@@ -81,7 +81,7 @@ unless ( condition ) {
}
# Это более читаемый вариант для "if (!condition)"
-# Специфические Perl-овые пост-условия:
+# Специфические Perl-овые пост-условия:
print "Yow!" if $zippy;
print "We have no bananas" unless $bananas;
@@ -129,7 +129,7 @@ open(my $out, ">", "output.txt") or die "Can't open output.txt: $!";
open(my $log, ">>", "my.log") or die "Can't open my.log: $!";
# Читать из файлового дескриптора можно с помощью оператора "<>".
-# В скалярном контексте он читает одну строку из файла, в списковом --
+# В скалярном контексте он читает одну строку из файла, в списковом --
# читает сразу весь файл, сохраняя по одной строке в элементе массива:
my $line = <$in>;
@@ -152,13 +152,13 @@ logger("We have a logger subroutine!");
#### Perl-модули
-Perl-овые модули предоставляют широкий набор функциональности,
-так что вы можете не изобретать заново велосипеды, а просто скачать
-нужный модуль с CPAN (http://www.cpan.org/).
-Некоторое количество самых полезных модулей включено в стандартную
+Perl-овые модули предоставляют широкий набор функциональности,
+так что вы можете не изобретать заново велосипеды, а просто скачать
+нужный модуль с CPAN (http://www.cpan.org/).
+Некоторое количество самых полезных модулей включено в стандартную
поставку Perl.
-Раздел документации perlfaq содержит вопросы и ответы о многих частых
+Раздел документации perlfaq содержит вопросы и ответы о многих частых
задачах, и часто предлагает подходящие CPAN-модули.
diff --git a/ru-ru/php-composer-ru.html.markdown b/ru-ru/php-composer-ru.html.markdown
new file mode 100644
index 00000000..4bdf1029
--- /dev/null
+++ b/ru-ru/php-composer-ru.html.markdown
@@ -0,0 +1,197 @@
+---
+category: tool
+tool: composer
+contributors:
+ - ["Brett Taylor", "https://github.com/glutnix"]
+translators:
+ - ["Aleksey 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
+# Если вы используете этот подход, вам нужно будет вызвать Composer следующим образом:
+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 # краткий вариант
+
+# Обновление Composer до последней версии
+composer self-update
+composer self # краткий вариант
+```
+
+# Использование
+
+Composer сохраняет ваши зависимости проекта в `composer.json`.
+Вы можете отредактировать этот файл, но лучше всего позволить Composer управлять им за вас.
+
+```sh
+# Создать новый проект в текущей папке
+composer init
+# запускается интерактивная анкета с просьбой предоставить подробную информацию о вашем проекте.
+# Вы прекрасно можете оставить ответы пустыми, если не делаете другие проекты
+# зависимыми от создаваемого проекта.
+
+# Если файл composer.json уже существует, загрузите зависимости
+composer install
+
+# Чтобы загрузить только зависимости для готового продукта, т.е.
+# исключая зависимости для разработки
+composer install --no-dev
+
+# Добавить зависимость для готового продукта к этому проекту
+composer require guzzlehttp/guzzle
+# выяснит, какая существует последняя версия guzzlehttp / guzzle,
+# загрузит её и добавит новую зависимость в поле require файла composer.json.
+
+composer require guzzlehttp/guzzle:6.0.*
+# Загрузит последнюю версию, соответствующую шаблону (например, 6.0.2),
+# и добавит зависимость к полю require файла composer.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 см.
+# [Документацию 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` и `composer.lock`
+
+Файл `composer.json` хранит параметры допустимых версий каждой зависимости
+вашего проекта, а также другую информацию.
+
+
+Файл `composer.lock` хранит точную загруженную версию каждой зависимости.
+Никогда не редактируйте этот файл.
+
+Если вы включите файл `composer.lock` в свой Git-репозиторий,
+каждый разработчик установит версии зависимостей, которые вы используете.
+Даже когда будет выпущена новая версия зависимости, Composer продолжит загрузку версии,
+записанной в lock-файле.
+
+```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-совместимый автозагрузчик
+
+
+Вы можете добавить в автозагрузчик свои собственные пространства имён.
+
+Добавьте поле `autoload` в `composer.json`:
+
+```json
+{
+ "autoload": {
+ "psr-4": {"Acme\\": "src/"}
+ }
+}
+```
+Это скажет автозагрузчику искать что-либо в пространстве имён `\Acme` в папке `src`.
+
+Вы также можете использовать
+[PSR-0, карту классов или просто список файлов для включения](https://getcomposer.org/doc/04-schema.md#autoload).
+Также существует поле `autoload-dev` для пространств имён, предназначенных только для разработки.
+
+При добавлении или изменении ключа автозагрузки вам необходимо перестроить автозагрузчик:
+
+```sh
+composer dump-autoload
+composer dump # краткий вариант
+
+# Оптимизирует пакеты 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
+
+### Ссылки
+
+* [Composer - Dependency Manager for PHP](https://getcomposer.org/)
+* [Packagist.org](https://packagist.org/)
diff --git a/ru-ru/php-ru.html.markdown b/ru-ru/php-ru.html.markdown
index 181368de..af77a9ca 100644
--- a/ru-ru/php-ru.html.markdown
+++ b/ru-ru/php-ru.html.markdown
@@ -61,6 +61,8 @@ $int4 = 0x0F; // => 15 (ведущие символы 0x означают шес
// Двоичная запись integer доступна начиная с PHP 5.4.0.
$int5 = 0b11111111; // 255 (0b в начале означает двоичное число)
+// Удаление переменной
+unset($int1);
// Дробные числа
$float = 1.234;
@@ -128,7 +130,7 @@ define("FOO", "something");
// Доступ к константе возможен через прямое указание её имени без знака $
echo FOO; // печатает 'something'
-echo 'This outputs ' . FOO; // печатает 'This ouputs something'
+echo 'This outputs ' . FOO; // печатает 'This outputs something'
/********************************
* Массивы
@@ -687,45 +689,6 @@ use My\Namespace as SomeOtherNamespace;
$cls = new SomeOtherNamespace\MyClass();
-*//**********************
-* Позднее статическое связывание.
-*
-*/
-
-class ParentClass
-{
- public static function who()
- {
- echo "I'm a " . __CLASS__ . "\n";
- }
-
- public static function test()
- {
- // self ссылается на класс в котором определен метод.
- self::who();
- // static ссылается на класс в котором метод вызван.
- static::who();
- }
-}
-
-ParentClass::test();
-/*
-I'm a ParentClass
-I'm a ParentClass
-*/
-
-class ChildClass extends ParentClass
-{
- public static function who()
- {
- echo "But I'm " . __CLASS__ . "\n";
- }
-}
-
-ChildClass::test();
-/*
-I'm a ParentClass
-But I'm ChildClass
/**********************
* Позднее статическое связывание.
diff --git a/ru-ru/pyqt-ru.html.markdown b/ru-ru/pyqt-ru.html.markdown
new file mode 100644
index 00000000..24afc03d
--- /dev/null
+++ b/ru-ru/pyqt-ru.html.markdown
@@ -0,0 +1,86 @@
+---
+category: tool
+tool: PyQT
+lang: ru-ru
+filename: learnpyqt-ru.py
+contributors:
+ - ["Nathan Hughes", "https://github.com/sirsharpest"]
+translators:
+ - ["Vadim Toptunov", "https://github.com/VadimToptunov"]
+---
+
+**Qt** - широко известный кросс-платформенный фреймворк для разработки программного обеспечения,
+который может быть использован на различных софтварных и хардварных платформах без какого-либо
+изменения в коде. Данный фреймворк при этом обладает мощью и скоростью нативных приложений.
+Qt и был изначально написан на *C++*.
+
+Данный текст является адаптацией введения в Qt на C++ под авторством Алексея Ковальчука для pyqt.
+
+
+```python
+
+def window():
+ # Создайте объект приложения
+ app = QtGui.QApplication(sys.argv)
+ # Создайте виджет, где будет находиться наш лейбл
+ w = QtGui.QWidget()
+ # Добавьте лейбл в виджет
+ b = QtGui.QLabel(w)
+ # Задайте текст для лейбла
+ b.setText("Hello World!")
+ # Задайте информация о размере и расположении
+ w.setGeometry(100, 100, 200, 50)
+ b.move(50, 20)
+ # Задайте заголовок окна
+ w.setWindowTitle("PyQt")
+ # Все ранее написанное выводится на экран
+ w.show()
+ # Настройка
+ sys.exit(app.exec_())
+
+if __name__ == '__main__':
+ window()
+
+```
+
+Для того, чтобы получить более продвинутые функции приложения в pyqt, нам необходимо
+обратить внимание на создание дополнительных элементов. Ниже представлено создание всплывающего диалогового окна, которое просит пользователя подтвердить его решение или предоставить какую-либо
+информацию.
+
+```Python
+import sys
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+
+
+def window():
+ app = QApplication(sys.argv)
+ w = QWidget()
+ # Создайте кнопку и прикрепите ее к виджету w
+ b = QPushButton(w)
+ b.setText("Press me")
+ b.move(50, 50)
+ # Укажите b вызвать эту функцию при клике мышкой
+ # Заметьте, что в вызове функции отсутствуют "()"
+ b.clicked.connect(showdialog)
+ w.setWindowTitle("PyQt Dialog")
+ w.show()
+ sys.exit(app.exec_())
+
+Данная функция должна создавать диалоговое окно с кнопкой, которая ждет клика по себе
+и затем завершает программу.
+
+def showdialog():
+ d = QDialog()
+ b1 = QPushButton("ok", d)
+ b1.move(50, 50)
+ d.setWindowTitle("Dialog")
+ # Эта модальность сообщает всплывающему окну блокировать родительский элемент, пока он активен
+ d.setWindowModality(Qt.ApplicationModal)
+ # Процесс завершается по клику мышкой
+ b1.clicked.connect(sys.exit)
+ d.exec_()
+
+if __name__ == '__main__':
+ window()
+```
diff --git a/ru-ru/python-ru.html.markdown b/ru-ru/python-ru.html.markdown
index 43142eff..e0e53b9c 100644
--- a/ru-ru/python-ru.html.markdown
+++ b/ru-ru/python-ru.html.markdown
@@ -1,27 +1,30 @@
---
-language: python
+language: Python
lang: ru-ru
contributors:
- ["Louie Dinh", "http://ldinh.ca"]
+ - ["Steven Basart", "http://github.com/xksteven"]
translators:
- - ["Yury Timofeev", "http://twitter.com/gagar1n"]
- ["Andre Polykanine", "https://github.com/Oire"]
+ - ["Anton Grouchtchak", "https://github.com/Teraskull"]
filename: learnpython-ru.py
---
Язык Python был создан Гвидо ван Россумом в начале 90-х. Сейчас это один из
самых популярных языков. Я влюбился в Python за понятный и доходчивый синтаксис — это
-почти исполняемый псевдокод.
+почти что исполняемый псевдокод.
С благодарностью жду ваших отзывов: [@louiedinh](http://twitter.com/louiedinh)
или louiedinh [at] [почтовый сервис Google]
-Замечание: Эта статья относится к Python 2.7, но должно работать и в других версиях Python 2.x.
-Чтобы изучить Python 3.x, обратитесь к статье по Python 3.
+Замечание: Эта статья относится только к Python 3.
+Если вы хотите изучить Python 2.7, обратитесь к другой статье.
```python
+
# Однострочные комментарии начинаются с символа решётки.
-""" Многострочный текст может быть
+
+""" Многострочный текст может быть
записан, используя 3 знака " и обычно используется
в качестве встроенной документации
"""
@@ -31,323 +34,397 @@ filename: learnpython-ru.py
####################################################
# У вас есть числа
-3 #=> 3
+3 # => 3
# Математика работает вполне ожидаемо
-1 + 1 #=> 2
-8 - 1 #=> 7
-10 * 2 #=> 20
-35 / 5 #=> 7
-
-# А вот деление немного сложнее. В этом случае происходит деление
-# целых чисел, и результат автоматически округляется в меньшую сторону.
-5 / 2 #=> 2
-
-# Чтобы делить правильно, сначала нужно немного узнать о числах
-# с плавающей запятой.
-2.0 # Это число с плавающей запятой
-11.0 / 4.0 #=> 2.75 Вооот... Так гораздо лучше
+1 + 1 # => 2
+8 - 1 # => 7
+10 * 2 # => 20
+35 / 5 # => 7.0
# Результат целочисленного деления округляется в меньшую сторону
# как для положительных, так и для отрицательных чисел.
-5 // 3 # => 1
-5.0 // 3.0 # => 1.0 # работает и для чисел с плавающей запятой
--5 // 3 # => -2
+5 // 3 # => 1
+-5 // 3 # => -2
+5.0 // 3.0 # => 1.0 # работает и для чисел с плавающей запятой
-5.0 // 3.0 # => -2.0
+# # Результат деления возвращает число с плавающей запятой
+10.0 / 3 # => 3.3333333333333335
+
# Остаток от деления
-7 % 3 # => 1
+7 % 3 # => 1
# Возведение в степень
-2**4 # => 16
+2**3 # => 8
# Приоритет операций указывается скобками
-(1 + 3) * 2 #=> 8
+1 + 3 * 2 # => 7
+(1 + 3) * 2 # => 8
-# Логические операторы
-# Обратите внимание: ключевые слова «and» и «or» чувствительны к регистру букв
-True and False #=> False
-False or True #=> True
-
-# Обратите внимание, что логические операторы используются и с целыми числами
-0 and 2 #=> 0
--5 or 0 #=> -5
-0 == False #=> True
-2 == True #=> False
-1 == True #=> True
+# Булевы значения - примитивы (Обратите внимание на заглавную букву)
+True # => True
+False # => False
# Для отрицания используется ключевое слово not
-not True #=> False
-not False #=> True
+not True # => False
+not False # => True
+
+# Булевы операторы
+# Обратите внимание: ключевые слова "and" и "or" чувствительны к регистру букв
+True and False # => False
+False or True # => True
+
+# True и False на самом деле 1 и 0, но с разными ключевыми словами
+True + True # => 2
+True * 8 # => 8
+False - 5 # => -5
+
+# Операторы сравнения обращают внимание на числовое значение True и False
+0 == False # => True
+1 == True # => True
+2 == True # => False
+-5 != False # => True
+
+# Использование булевых логических операторов на типах int превращает их в булевы значения, но возвращаются оригинальные значения
+# Не путайте с bool(ints) и bitwise and/or (&,|)
+bool(0) # => False
+bool(4) # => True
+bool(-6) # => True
+0 and 2 # => 0
+-5 or 0 # => -5
# Равенство — это ==
-1 == 1 #=> True
-2 == 1 #=> False
+1 == 1 # => True
+2 == 1 # => False
# Неравенство — это !=
-1 != 1 #=> False
-2 != 1 #=> True
+1 != 1 # => False
+2 != 1 # => True
# Ещё немного сравнений
-1 < 10 #=> True
-1 > 10 #=> False
-2 <= 2 #=> True
-2 >= 2 #=> True
-
-# Сравнения могут быть записаны цепочкой!
-1 < 2 < 3 #=> True
-2 < 3 < 2 #=> False
+1 < 10 # => True
+1 > 10 # => False
+2 <= 2 # => True
+2 >= 2 # => True
+
+# Проверка, находится ли значение в диапазоне
+1 < 2 and 2 < 3 # => True
+2 < 3 and 3 < 2 # => False
+
+# Сравнения могут быть записаны цепочкой
+1 < 2 < 3 # => True
+2 < 3 < 2 # => False
+
+# (is vs. ==) ключевое слово is проверяет, относятся ли две переменные к одному и тому же объекту, но == проверяет если указанные объекты имеют одинаковые значения.
+a = [1, 2, 3, 4] # a указывает на новый список, [1, 2, 3, 4]
+b = a # b указывает на то, что указывает a
+b is a # => True, a и b относятся к одному и тому же объекту
+b == a # => True, Объекты a и b равны
+b = [1, 2, 3, 4] # b указывает на новый список, [1, 2, 3, 4]
+b is a # => False, a и b не относятся к одному и тому же объекту
+b == a # => True, Объекты a и b равны
# Строки определяются символом " или '
"Это строка."
'Это тоже строка.'
-# И строки тоже можно складывать!
-"Привет " + "мир!" #=> "Привет мир!"
+# И строки тоже могут складываться! Хотя лучше не злоупотребляйте этим.
+"Привет " + "мир!" # => "Привет мир!"
-# ... или умножать
-"Привет" * 3 # => "ПриветПриветПривет"
+# Строки (но не переменные) могут быть объединены без использования '+'
+"Привет " "мир!" # => "Привет мир!"
# Со строкой можно работать, как со списком символов
-"Это строка"[0] #=> 'Э'
+"Привет мир!"[0] # => 'П'
-# Символ % используется для форматирования строк, например:
-"%s могут быть %s" % ("строки", "интерполированы")
+# Вы можете найти длину строки
+len("Это строка") # => 10
-# Новый способ форматирования строк — использование метода format.
-# Это предпочитаемый способ.
-"{0} могут быть {1}".format("строки", "форматированы")
+# Вы также можете форматировать, используя f-строки (в Python 3.6+)
+name = "Рейко"
+f"Она сказала, что ее зовут {name}." # => "Она сказала, что ее зовут Рейко"
+# Вы можете поместить любой оператор Python в фигурные скобки, и он будет выведен в строке.
+f"{name} состоит из {len(name)} символов." # => "Рэйко состоит из 5 символов."
-# Если вы не хотите считать, можете использовать ключевые слова.
-"{name} хочет есть {food}".format(name="Боб", food="лазанью")
# None является объектом
-None #=> None
+None # => None
-# Не используйте оператор равенства '=='' для сравнения
-# объектов с None. Используйте для этого «is»
-"etc" is None #=> False
-None is None #=> True
+# Не используйте оператор равенства "==" для сравнения
+# объектов с None. Используйте для этого "is"
+"etc" is None # => False
+None is None # => True
-# Оператор 'is' проверяет идентичность объектов. Он не
-# очень полезен при работе с примитивными типами, но
-# зато просто незаменим при работе с объектами.
-
-# None, 0 и пустые строки/списки равны False.
+# None, 0 и пустые строки/списки/словари/кортежи приводятся к False.
# Все остальные значения равны True
-0 == False #=> True
-"" == False #=> True
+bool(0) # => False
+bool("") # => False
+bool([]) # => False
+bool({}) # => False
+bool(()) # => False
####################################################
-## 2. Переменные и коллекции
+## 2. Переменные и Коллекции
####################################################
-# В Python есть оператор print, доступный в версиях 2.x, но удалённый в версии 3
-print "Я Python. Приятно познакомиться!"
-# В Python также есть функция print(), доступная в версиях 2.7 и 3,
-# Но для версии 2.7 нужно добавить следующий импорт модуля (раскомментируйте)):
-# from __future__ import print_function
-print("Я тоже Python! ")
+# В Python есть функция Print
+print("Я Python. Приятно познакомиться!") # => Я Python. Приятно познакомиться!
+
+# По умолчанию функция, print() также выводит новую строку в конце.
+# Используйте необязательный аргумент end, чтобы изменить последнюю строку.
+print("Привет мир", end="!") # => Привет мир!
+
+# Простой способ получить входные данные из консоли
+input_string_var = input("Введите данные: ") # Возвращает данные в виде строки
+# Примечание: в более ранних версиях Python метод input() назывался raw_input()
# Объявлять переменные перед инициализацией не нужно.
-some_var = 5 # По соглашению используется нижний_регистр_с_подчёркиваниями
-some_var #=> 5
+# По соглашению используется нижний_регистр_с_подчёркиваниями
+some_var = 5
+some_var # => 5
-# При попытке доступа к неинициализированной переменной
-# выбрасывается исключение.
-# См. раздел «Поток управления» для информации об исключениях.
-some_other_var # Выбрасывает ошибку именования
+# При попытке доступа к неинициализированной переменной выбрасывается исключение.
+# Об исключениях см. раздел "Поток управления и итерируемые объекты".
+some_unknown_var # Выбрасывает ошибку NameError
-# if может быть использован как выражение
-"yahoo!" if 3 > 2 else 2 #=> "yahoo!"
+# if можно использовать как выражение
+# Эквивалент тернарного оператора '?:' в C
+"да!" if 0 > 1 else "нет!" # => "нет!"
# Списки хранят последовательности
li = []
# Можно сразу начать с заполненного списка
other_li = [4, 5, 6]
-# строка разделена в список
-a="adambard"
-list(a) #=> ['a','d','a','m','b','a','r','d']
-
-# Объекты добавляются в конец списка методом append
-li.append(1) # [1]
-li.append(2) # [1, 2]
-li.append(4) # [1, 2, 4]
-li.append(3) # [1, 2, 4, 3]
-# И удаляются с конца методом pop
-li.pop() #=> возвращает 3 и li становится равен [1, 2, 4]
+# Объекты добавляются в конец списка методом append()
+li.append(1) # [1]
+li.append(2) # [1, 2]
+li.append(4) # [1, 2, 4]
+li.append(3) # [1, 2, 4, 3]
+# И удаляются с конца методом pop()
+li.pop() # => возвращает 3 и li становится равен [1, 2, 4]
# Положим элемент обратно
-li.append(3) # [1, 2, 4, 3].
+li.append(3) # [1, 2, 4, 3].
# Обращайтесь со списком, как с обычным массивом
-li[0] #=> 1
-# Присваивайте новые значения уже инициализированным индексам с помощью =
-li[0] = 42
-li[0] # => 42
-li[0] = 1 # Обратите внимание: возвращаемся на исходное значение
+li[0] # => 1
+
# Обратимся к последнему элементу
-li[-1] #=> 3
+li[-1] # => 3
# Попытка выйти за границы массива приведёт к ошибке индекса
-li[4] # Выдаёт IndexError
+li[4] # Выбрасывает ошибку IndexError
# Можно обращаться к диапазону, используя так называемые срезы
# (Для тех, кто любит математику, это называется замкнуто-открытый интервал).
-li[1:3] #=> [2, 4]
-# Опускаем начало
-li[2:] #=> [4, 3]
-# Опускаем конец
-li[:3] #=> [1, 2, 4]
-# Выбираем каждый второй элемент
-li[::2] # =>[1, 4]
-# Переворачиваем список
-li[::-1] # => [3, 4, 2, 1]
+li[1:3] # Вернуть список из индекса с 1 по 3 => [2, 4]
+li[2:] # Вернуть список, начиная с индекса 2 => [4, 3]
+li[:3] # Вернуть список с начала до индекса 3 => [1, 2, 4]
+li[::2] # Вернуть список, выбирая каждую вторую запись => [1, 4]
+li[::-1] # Вернуть список в обратном порядке => [3, 4, 2, 1]
# Используйте сочетания всего вышеназванного для выделения более сложных срезов
# li[начало:конец:шаг]
+# Сделать однослойную глубокую копию, используя срезы
+li2 = li[:] # => li2 = [1, 2, 4, 3], но (li2 is li) вернет False.
+
# Удаляем произвольные элементы из списка оператором del
-del li[2] # li теперь [1, 2, 3]
+del li[2] # [1, 2, 3]
+
+# Удалить первое вхождение значения
+li.remove(2) # [1, 3]
+li.remove(2) # Выбрасывает ошибку ValueError поскольку 2 нет в списке
+
+# Вставить элемент по определенному индексу
+li.insert(1, 2) # [1, 2, 3]
+
+# Получить индекс первого найденного элемента, соответствующего аргументу
+li.index(2) # => 1
+li.index(4) # Выбрасывает ошибку ValueError поскольку 4 нет в списке
# Вы можете складывать, или, как ещё говорят, конкатенировать списки
-li + other_li #=> [1, 2, 3, 4, 5, 6] — Замечание: li и other_li не изменяются
# Обратите внимание: значения li и other_li при этом не изменились.
+li + other_li # => [1, 2, 3, 4, 5, 6]
-# Объединять списки можно методом extend
+# Объединять списки можно методом extend()
li.extend(other_li) # Теперь li содержит [1, 2, 3, 4, 5, 6]
-# Проверить элемент на вхождение в список можно оператором in
-1 in li #=> True
+# Проверить элемент на наличие в списке можно оператором in
+1 in li # => True
# Длина списка вычисляется функцией len
-len(li) #=> 6
+len(li) # => 6
-# Кортежи — это такие списки, только неизменяемые
+# Кортежи похожи на списки, только неизменяемые
tup = (1, 2, 3)
-tup[0] #=> 1
-tup[0] = 3 # Выдаёт TypeError
+tup[0] # => 1
+tup[0] = 3 # Выбрасывает ошибку TypeError
+
+# Обратите внимание, что кортеж длины 1 должен иметь запятую после последнего элемента, но кортежи другой длины, даже 0, не должны.
+type((1)) # => <class 'int'>
+type((1,)) # => <class 'tuple'>
+type(()) # => <class 'tuple'>
# Всё то же самое можно делать и с кортежами
-len(tup) #=> 3
-tup + (4, 5, 6) #=> (1, 2, 3, 4, 5, 6)
-tup[:2] #=> (1, 2)
-2 in tup #=> True
+len(tup) # => 3
+tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
+tup[:2] # => (1, 2)
+2 in tup # => True
# Вы можете распаковывать кортежи (или списки) в переменные
-a, b, c = (1, 2, 3) # a == 1, b == 2 и c == 3
+a, b, c = (1, 2, 3) # a == 1, b == 2 и c == 3
+# Вы также можете сделать расширенную распаковку
+a, *b, c = (1, 2, 3, 4) # a теперь 1, b теперь [2, 3] и c теперь 4
# Кортежи создаются по умолчанию, если опущены скобки
-d, e, f = 4, 5, 6
+d, e, f = 4, 5, 6 # кортеж 4, 5, 6 распаковывается в переменные d, e и f
+# соответственно, d = 4, e = 5 и f = 6
# Обратите внимание, как легко поменять местами значения двух переменных
-e, d = d, e # теперь d == 5, а e == 4
+e, d = d, e # теперь d == 5, а e == 4
-# Словари содержат ассоциативные массивы
+
+# Словари содержат ассоциативные массивы
empty_dict = {}
# Вот так описывается предзаполненный словарь
filled_dict = {"one": 1, "two": 2, "three": 3}
-# Значения извлекаются так же, как из списка, с той лишь разницей,
-# что индекс — у словарей он называется ключом — не обязан быть числом
-filled_dict["one"] #=> 1
+# Обратите внимание, что ключи для словарей должны быть неизменяемыми типами. Это
+# сделано для того, чтобы ключ может быть преобразован в хеш для быстрого поиска.
+# Неизменяемые типы включают целые числа, числа с плавающей запятой, строки, кортежи.
+invalid_dict = {[1,2,3]: "123"} # => Выбрасывает ошибку TypeError: unhashable type: 'list'
+valid_dict = {(1,2,3):[1,2,3]} # Однако значения могут быть любого типа.
+
+# Поиск значений с помощью []
+filled_dict["one"] # => 1
-# Можно получить все ключи в виде списка с помощью метода keys
-filled_dict.keys() #=> ["three", "two", "one"]
-# Замечание: сохранение порядка ключей в словаре не гарантируется
-# Ваши результаты могут не совпадать с этими.
+# Все ключи в виде списка получаются с помощью метода keys().
+# Его вызов нужно обернуть в list(), так как обратно мы получаем
+# итерируемый объект, о которых поговорим позднее. Примечание - для Python
+# версии <3.7, порядок словарных ключей не гарантируется. Ваши результаты могут
+# не точно соответствовать приведенному ниже примеру. Однако, начиная с Python 3.7
+# элементы в словаре сохраняют порядок, в котором они вставляются в словарь.
+list(filled_dict.keys()) # => ["three", "two", "one"] в Python <3.7
+list(filled_dict.keys()) # => ["one", "two", "three"] в Python 3.7+
-# Можно получить и все значения в виде списка, используйте метод values
-filled_dict.values() #=> [3, 2, 1]
+
+# Все значения в виде списка можно получить с помощью values().
+# И снова нам нужно обернуть вызов в list(), чтобы превратить
+# итерируемый объект в список.
# То же самое замечание насчёт порядка ключей справедливо и здесь
+list(filled_dict.values()) # => [3, 2, 1] в Python <3.7
+list(filled_dict.values()) # => [1, 2, 3] в Python 3.7+
-# При помощи оператора in можно проверять ключи на вхождение в словарь
-"one" in filled_dict #=> True
-1 in filled_dict #=> False
+# При помощи ключевого слова in можно проверять наличие ключей в словаре
+"one" in filled_dict # => True
+1 in filled_dict # => False
-# Попытка получить значение по несуществующему ключу выбросит ошибку ключа
-filled_dict["four"] # KeyError
+# Попытка получить значение по несуществующему ключу выбросит ошибку KeyError
+filled_dict["four"] # Выбрасывает ошибку KeyError
# Чтобы избежать этого, используйте метод get()
-filled_dict.get("one") #=> 1
-filled_dict.get("four") #=> None
-# Метод get также принимает аргумент по умолчанию, значение которого будет
-# возвращено при отсутствии указанного ключа
-filled_dict.get("one", 4) #=> 1
-filled_dict.get("four", 4) #=> 4
-# Обратите внимание, что filled_dict.get("four") всё ещё => None
-# (get не устанавливает значение элемента словаря)
-
-# Присваивайте значение ключам так же, как и в списках
-filled_dict["four"] = 4 # теперь filled_dict["four"] => 4
+filled_dict.get("one") # => 1
+filled_dict.get("four") # => None
+# Метод get поддерживает аргумент по умолчанию, когда значение отсутствует
+filled_dict.get("one", 4) # => 1
+filled_dict.get("four", 4) # => 4
# Метод setdefault() вставляет пару ключ-значение, только если такого ключа нет
-filled_dict.setdefault("five", 5) #filled_dict["five"] возвращает 5
-filled_dict.setdefault("five", 6) #filled_dict["five"] по-прежнему возвращает 5
+filled_dict.setdefault("five", 5) # filled_dict["five"] возвращает 5
+filled_dict.setdefault("five", 6) # filled_dict["five"] по-прежнему возвращает 5
+
+# Добавление элементов в словарь
+filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4}
+filled_dict["four"] = 4 # Другой способ добавления элементов
+
+# Удаляйте ключи из словаря с помощью ключевого слова del
+del filled_dict["one"] # Удаляет ключ "one" из словаря
+
+# После Python 3.5 вы также можете использовать дополнительные параметры распаковки
+{'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2}
+{'a': 1, **{'a': 2}} # => {'a': 2}
+
# Множества содержат... ну, в общем, множества
-# (которые похожи на списки, только в них не может быть дублирующихся элементов)
empty_set = set()
-# Инициализация множества набором значений
-some_set = set([1,2,2,3,4]) # some_set теперь равно set([1, 2, 3, 4])
-
-# Порядок сортировки не гарантируется, хотя иногда они выглядят отсортированными
-another_set = set([4, 3, 2, 2, 1]) # another_set теперь set([1, 2, 3, 4])
+# Инициализация множества набором значений.
+# Да, оно выглядит примерно как словарь. Ну извините, так уж вышло.
+filled_set = {1, 2, 2, 3, 4} # => {1, 2, 3, 4}
-# Начиная с Python 2.7, вы можете использовать {}, чтобы объявить множество
-filled_set = {1, 2, 2, 3, 4} # => {1, 2, 3, 4}
+# Similar to keys of a dictionary, elements of a set have to be immutable.
+# Как и ключи словаря, элементы множества должны быть неизменяемыми.
+invalid_set = {[1], 1} # => Выбрасывает ошибку TypeError: unhashable type: 'list'
+valid_set = {(1,), 1}
-# Добавление новых элементов в множество
-filled_set.add(5) # filled_set равно {1, 2, 3, 4, 5}
+# Множеству можно назначать новую переменную
+filled_set = some_set
+filled_set.add(5) # {1, 2, 3, 4, 5}
+# В множествах нет повторяющихся элементов
+filled_set.add(5) # {1, 2, 3, 4, 5}
# Пересечение множеств: &
other_set = {3, 4, 5, 6}
-filled_set & other_set #=> {3, 4, 5}
+filled_set & other_set # => {3, 4, 5}
# Объединение множеств: |
-filled_set | other_set #=> {1, 2, 3, 4, 5, 6}
+filled_set | other_set # => {1, 2, 3, 4, 5, 6}
# Разность множеств: -
-{1,2,3,4} - {2,3,5} #=> {1, 4}
+{1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
-# Проверка на вхождение во множество: in
-2 in filled_set #=> True
-10 in filled_set #=> False
+# Симметричная разница: ^
+{1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5}
+
+# Проверить, является ли множество слева надмножеством множества справа
+{1, 2} >= {1, 2, 3} # => False
+
+# Проверить, является ли множество слева подмножеством множества справа
+{1, 2} <= {1, 2, 3} # => True
+
+# Проверка на наличие в множестве: in
+2 in filled_set # => True
+10 in filled_set # => False
+
+# Сделать однослойную глубокую копию
+filled_set = some_set.copy() # {1, 2, 3, 4, 5}
+filled_set is some_set # => False
####################################################
-## 3. Поток управления
+## 3. Поток управления и итерируемые объекты
####################################################
-# Для начала заведём переменную
+# Для начала создадим переменную
some_var = 5
# Так выглядит выражение if. Отступы в python очень важны!
-# результат: «some_var меньше, чем 10»
+# Конвенция заключается в использовании четырех пробелов, а не табуляции.
+# Pезультат: "some_var меньше, чем 10"
if some_var > 10:
- print("some_var намного больше, чем 10.")
-elif some_var < 10: # Выражение elif необязательно.
+ print("some_var точно больше, чем 10.")
+elif some_var < 10: # Выражение elif необязательно.
print("some_var меньше, чем 10.")
-else: # Это тоже необязательно.
+else: # Это тоже необязательно.
print("some_var равно 10.")
"""
-Циклы For проходят по спискам
-
-Результат:
+Циклы For проходят по спискам.
+Выводит:
собака — это млекопитающее
кошка — это млекопитающее
мышь — это млекопитающее
"""
for animal in ["собака", "кошка", "мышь"]:
- # Можете использовать оператор % для интерполяции форматированных строк
- print("%s — это млекопитающее" % animal)
-
+ # Можете использовать format() для интерполяции форматированных строк
+ print("{} — это млекопитающее".format(animal))
+
"""
-«range(число)» возвращает список чисел
+"range(число)" возвращает список чисел
от нуля до заданного числа
-Результат:
+Выводит:
0
1
2
@@ -357,8 +434,42 @@ for i in range(4):
print(i)
"""
+"range(нижнее, верхнее)" возвращает список чисел
+от нижнего числа к верхнему
+Выводит:
+ 4
+ 5
+ 6
+ 7
+"""
+for i in range(4, 8):
+ print(i)
+
+"""
+"range(нижнее, верхнее, шаг)" возвращает список чисел
+от нижнего числа к верхнему, от нижнего числа к верхнему, увеличивая
+шаг за шагом. Если шаг не указан, значение по умолчанию - 1.
+Выводит:
+ 4
+ 6
+"""
+for i in range(4, 8, 2):
+ print(i)
+
+"""
+Чтобы перебрать список и получить индекс и значение каждого элемента в списке
+Выводит:
+ 0 собака
+ 1 кошка
+ 2 мышь
+"""
+animals = ["собака", "кошка", "мышь"]
+for i, value in enumerate(animals):
+ print(i, value)
+
+"""
Циклы while продолжаются до тех пор, пока указанное условие не станет ложным.
-Результат:
+Выводит:
0
1
2
@@ -370,20 +481,81 @@ while x < 4:
x += 1 # Краткая запись для x = x + 1
# Обрабатывайте исключения блоками try/except
-
-# Работает в Python 2.6 и выше:
try:
# Чтобы выбросить ошибку, используется raise
raise IndexError("Это ошибка индекса")
except IndexError as e:
- # pass — это просто отсутствие оператора. Обычно здесь происходит
- # восстановление после ошибки.
- pass
+ pass # pass — это просто отсутствие оператора. Обычно здесь происходит восстановление после ошибки.
except (TypeError, NameError):
- pass # Несколько исключений можно обработать вместе, если нужно.
-else: # Необязательное выражение. Должно следовать за последним блоком except
- print("Всё хорошо!") # Выполнится, только если не было никаких исключений
+ pass # Несколько исключений можно обработать вместе, если нужно.
+else: # Необязательное выражение. Должно следовать за последним блоком except
+ print("Всё хорошо!") # Выполнится, только если не было никаких исключений
+finally: # Выполнить при любых обстоятельствах
+ print("Мы можем очистить ресурсы здесь")
+
+# Вместо try/finally чтобы очистить ресурсы, можно использовать оператор with
+with open("myfile.txt") as f:
+ for line in f:
+ print(line)
+
+# Запись в файл
+contents = {"aa": 12, "bb": 21}
+with open("myfile1.txt", "w+") as file:
+ file.write(str(contents)) # Записывает строку в файл
+
+with open("myfile2.txt", "w+") as file:
+ file.write(json.dumps(contents)) # Записывает объект в файл
+
+# Чтение из файла
+with open('myfile1.txt', "r+") as file:
+ contents = file.read() # Читает строку из файла
+print(contents)
+# print: {"aa": 12, "bb": 21}
+
+with open('myfile2.txt', "r+") as file:
+ contents = json.load(file) # Читает объект json из файла
+print(contents)
+# print: {"aa": 12, "bb": 21}
+
+
+# Python предоставляет фундаментальную абстракцию,
+# которая называется итерируемым объектом (Iterable).
+# Итерируемый объект — это объект, который воспринимается как последовательность.
+# Объект, который возвратила функция range(), итерируемый.
+
+filled_dict = {"one": 1, "two": 2, "three": 3}
+our_iterable = filled_dict.keys()
+print(our_iterable) # => dict_keys(['one', 'two', 'three']). Это объект, реализующий интерфейс Iterable
+
+# Мы можем проходить по нему циклом.
+for i in our_iterable:
+ print(i) # Выводит one, two, three
+
+# Но мы не можем обращаться к элементу по индексу.
+our_iterable[1] # Выбрасывает ошибку TypeError
+
+# Итерируемый объект знает, как создавать итератор.
+our_iterator = iter(our_iterable)
+
+# Итератор может запоминать состояние при проходе по объекту.
+# Мы получаем следующий объект, вызывая функцию next().
+next(our_iterator) # => "one"
+# Он сохраняет состояние при вызове next().
+next(our_iterator) # => "two"
+next(our_iterator) # => "three"
+
+# Возвратив все данные, итератор выбрасывает исключение StopIterator
+next(our_iterator) # Выбрасывает исключение StopIteration
+
+# Мы можем проходить по нему циклом.
+our_iterator = iter(our_iterable)
+for i in our_iterator:
+ print(i) # Выводит one, two, three
+
+# Вы можете получить сразу все элементы итератора, вызвав на нём функцию list().
+list(our_iterable) # => Возвращает ["one", "two", "three"]
+list(our_iterator) # => Возвращает [] потому что состояние сохраняется
####################################################
@@ -393,30 +565,28 @@ else: # Необязательное выражение. Должно след
# Используйте def для создания новых функций
def add(x, y):
print("x равен %s, а y равен %s" % (x, y))
- return x + y # Возвращайте результат с помощью ключевого слова return
+ return x + y # Возвращайте результат с помощью ключевого слова return
# Вызов функции с аргументами
-add(5, 6) #=> выводит «x равен 5, а y равен 6» и возвращает 11
+add(5, 6) # => Выводит "x равен 5, а y равен 6" и возвращает 11
# Другой способ вызова функции — вызов с именованными аргументами
-add(y=6, x=5) # Именованные аргументы можно указывать в любом порядке.
+add(y=6, x=5) # Именованные аргументы можно указывать в любом порядке.
-# Вы можете определить функцию, принимающую переменное число аргументов,
-# которые будут интерпретированы как кортеж, если вы не используете *
+# Вы можете определить функцию, принимающую переменное число аргументов
def varargs(*args):
return args
-varargs(1, 2, 3) #=> (1,2,3)
+varargs(1, 2, 3) # => (1,2,3)
# А также можете определить функцию, принимающую переменное число
-# именованных аргументов, которые будут интерпретированы как словарь,
-# если вы не используете **
+# именованных аргументов
def keyword_args(**kwargs):
return kwargs
# Вызовем эту функцию и посмотрим, что из этого получится
-keyword_args(big="foot", loch="ness") #=> {"big": "foot", "loch": "ness"}
+keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"}
# Если хотите, можете использовать оба способа одновременно
def all_the_args(*args, **kwargs):
@@ -432,77 +602,134 @@ all_the_args(1, 2, a=3, b=4) выводит:
# Используйте символ * для распаковки кортежей и ** для распаковки словарей
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
-all_the_args(*args) # эквивалентно foo(1, 2, 3, 4)
-all_the_args(**kwargs) # эквивалентно foo(a=3, b=4)
-all_the_args(*args, **kwargs) # эквивалентно foo(1, 2, 3, 4, a=3, b=4)
-
-# вы можете передавать переменное число позиционных или именованных аргументов
-# другим функциям, которые их принимают, распаковывая их с помощью
-# * или ** соответственно
-def pass_all_the_args(*args, **kwargs):
- all_the_args(*args, **kwargs)
- print varargs(*args)
- print keyword_args(**kwargs)
+all_the_args(*args) # эквивалентно all_the_args(1, 2, 3, 4)
+all_the_args(**kwargs) # эквивалентно all_the_args(a=3, b=4)
+all_the_args(*args, **kwargs) # эквивалентно all_the_args(1, 2, 3, 4, a=3, b=4)
+
+# Возврат нескольких значений (с назначением кортежей)
+def swap(x, y):
+ return y, x # Возвращает несколько значений в виде кортежа без скобок.
+ # (Примечание: скобки исключены, но могут быть включены)
+
+x = 1
+y = 2
+x, y = swap(x, y) # => x = 2, y = 1
+# (x, y) = swap(x,y) # Снова, скобки были исключены, но могут быть включены.
# Область определения функций
x = 5
-def setX(num):
+def set_x(num):
# Локальная переменная x — это не то же самое, что глобальная переменная x
- x = num # => 43
- print (x) # => 43
-
-def setGlobalX(num):
+ x = num # => 43
+ print(x) # => 43
+
+def set_global_x(num):
global x
- print (x) # => 5
- x = num # Глобальная переменная x теперь равна 6
- print (x) # => 6
+ print(x) # => 5
+ x = num # Глобальная переменная x теперь равна 6
+ print(x) # => 6
-setX(43)
-setGlobalX(6)
+set_x(43)
+set_global_x(6)
-# В Python функции — «объекты первого класса»
+# Python имеет функции первого класса
def create_adder(x):
def adder(y):
return x + y
return adder
add_10 = create_adder(10)
-add_10(3) #=> 13
+add_10(3) # => 13
# Также есть и анонимные функции
-(lambda x: x > 2)(3) #=> True
+(lambda x: x > 2)(3) # => True
+(lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5
# Есть встроенные функции высшего порядка
-map(add_10, [1,2,3]) #=> [11, 12, 13]
-filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7]
+list(map(add_10, [1, 2, 3])) # => [11, 12, 13]
+list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3]
+
+list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7]
+
+# Для удобного отображения и фильтрации можно использовать списочные интерпретации
+# Интерпретация списка сохраняет вывод в виде списка, который сам может быть вложенным списком
+[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
+[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
+
+# Вы также можете создавать интерпретации множеств и словарей.
+{x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'}
+{x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
-# Для удобного отображения и фильтрации можно использовать списочные включения
-[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13]
-[x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7]
####################################################
-## 5. Классы
+## 5. Модули
####################################################
-# Чтобы получить класс, мы наследуемся от object.
-class Human(object):
+# Вы можете импортировать модули
+import math
+print(math.sqrt(16)) # => 4.0
+
+# Вы можете получить определенные функции из модуля
+from math import ceil, floor
+print(ceil(3.7)) # => 4.0
+print(floor(3.7)) # => 3.0
+
+# Вы можете импортировать все функции из модуля.
+# Предупреждение: это не рекомендуется
+from math import *
- # Атрибут класса. Он разделяется всеми экземплярами этого класса
- species = "H. sapiens"
+# Вы можете сократить имена модулей
+import math as m
+math.sqrt(16) == m.sqrt(16) # => True
+
+# Модули Python - это обычные файлы Python. Вы
+# можете писать свои собственные и импортировать их. Имя
+# модуля совпадает с именем файла.
+
+# Вы можете узнать, какие функции и атрибуты
+# определены в модуле.
+import math
+dir(math)
+
+# Если у вас есть скрипт Python с именем math.py в той же папке,
+# что и ваш текущий скрипт, файл math.py будет
+# будет загружен вместо встроенного модуля Python.
+# Это происходит потому, что локальная папка имеет приоритет
+# над встроенными библиотеками Python.
+
+
+####################################################
+## 6. Классы
+####################################################
+
+# Мы используем оператор class для создания класса
+class Human:
+
+ # Атрибут класса. Он используется всеми экземплярами этого класса
+ species = "Гомосапиенс"
# Обычный конструктор, вызывается при инициализации экземпляра класса
# Обратите внимание, что двойное подчёркивание в начале и в конце имени
# означает объекты и атрибуты, которые используются Python, но находятся
# в пространствах имён, управляемых пользователем.
+ # Методы (или объекты или атрибуты), например:
+ # __init__, __str__, __repr__ и т. д. называются специальными методами.
# Не придумывайте им имена самостоятельно.
def __init__(self, name):
- # Присваивание значения аргумента атрибуту класса name
+ # Присваивание значения аргумента атрибуту
self.name = name
+ # Инициализация свойства
+ self._age = 0
+
# Метод экземпляра. Все методы принимают self в качестве первого аргумента
def say(self, msg):
- return "%s: %s" % (self.name, msg)
+ return "{name}: {message}".format(name=self.name, message=msg)
+
+ # Другой метод экземпляра
+ def sing(self):
+ return 'йо... йо... проверка микрофона... раз, два... раз, два...'
# Метод класса разделяется между всеми экземплярами
# Они вызываются с указыванием вызывающего класса в качестве первого аргумента
@@ -515,58 +742,242 @@ class Human(object):
def grunt():
return "*grunt*"
+ # property похоже на геттер.
+ # Оно превращает метод age() в одноименный атрибут только для чтения.
+ # Однако нет необходимости писать тривиальные геттеры и сеттеры в Python.
+ @property
+ def age(self):
+ return self._age
+
+ # Это позволяет установить свойство
+ @age.setter
+ def age(self, age):
+ self._age = age
+
+ # Это позволяет удалить свойство
+ @age.deleter
+ def age(self):
+ del self._age
+
+
+# Когда интерпретатор Python читает исходный файл, он выполняет весь его код.
+# Проверка __name__ гарантирует, что этот блок кода выполняется только тогда, когда
+# этот модуль - это основная программа.
+if __name__ == '__main__':
+ # Инициализация экземпляра класса
+ i = Human(name="Иван")
+ i.say("привет") # Выводит: "Иван: привет"
+ j = Human("Пётр")
+ j.say("привет") # Выводит: "Пётр: привет"
+ # i и j являются экземплярами типа Human, или другими словами: они являются объектами Human
+
+ # Вызов метода класса
+ i.say(i.get_species()) # "Иван: Гомосапиенс"
+ # Изменение разделяемого атрибута
+ Human.species = "Неандертальец"
+ i.say(i.get_species()) # => "Иван: Неандертальец"
+ j.say(j.get_species()) # => "Пётр: Неандертальец"
+
+ # Вызов статического метода
+ print(Human.grunt()) # => "*grunt*"
+
+ # Невозможно вызвать статический метод с экземпляром объекта
+ # потому что i.grunt() автоматически поместит "self" (объект i) в качестве аргумента
+ print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given
+
+ # Обновить свойство для этого экземпляра
+ i.age = 42
+ # Получить свойство
+ i.say(i.age) # => "Иван: 42"
+ j.say(j.age) # => "Пётр: 0"
+ # Удалить свойство
+ del i.age
+ # i.age # => это выбрасило бы ошибку AttributeError
+
+
+####################################################
+## 6.1 Наследование
+####################################################
+
+# Наследование позволяет определять новые дочерние классы, которые наследуют методы и
+# переменные от своего родительского класса.
+
+# Используя класс Human, определенный выше как базовый или родительский класс, мы можем
+# определить дочерний класс Superhero, который наследует переменные класса, такие как
+# "species", "name" и "age", а также методы, такие как "sing" и "grunt" из класса Human,
+# но также может иметь свои уникальные свойства.
+
+# Чтобы воспользоваться преимуществами модульности по файлам, вы можете поместить
+# вышеперечисленные классы в их собственные файлы, например, human.py
+
+# Чтобы импортировать функции из других файлов, используйте следующий формат
+# from "имя-файла-без-расширения" import "функция-или-класс"
+
+from human import Human
+
+
+# Укажите родительский класс(ы) как параметры определения класса
+class Superhero(Human):
+
+ # Если дочерний класс должен наследовать все определения родителя без каких-либо
+ # изменений, вы можете просто использовать ключевое слово pass (и ничего больше),
+ # но в этом случае оно закомментировано, чтобы разрешить уникальный дочерний класс:
+ # pass
+
+ # Дочерние классы могут переопределять атрибуты своих родителей
+ species = 'Сверхчеловек'
+
+ # Дочерние классы автоматически наследуют конструктор родительского класса, включая
+ # его аргументы, но также могут определять дополнительные аргументы или определения
+ # и переопределять его методы, такие как конструктор класса.
+ # Этот конструктор наследует аргумент "name" от класса "Human"
+ # и добавляет аргументы "superpower" и "movie":
+ def __init__(self, name, movie=False,
+ superpowers=["сверхсила", "пуленепробиваемость"]):
+
+ # добавить дополнительные атрибуты класса:
+ self.fictional = True
+ self.movie = movie
+ # помните об изменяемых значениях по умолчанию,
+ # поскольку значения по умолчанию являются общими
+ self.superpowers = superpowers
+
+ # Функция "super" позволяет вам получить доступ к методам родительского класса,
+ # которые переопределяются дочерним, в данном случае, методом __init__.
+ # Это вызывает конструктор родительского класса:
+ super().__init__(name)
+
+ # переопределить метод sing
+ def sing(self):
+ return 'Бам, бам, БАМ!'
+
+ # добавить дополнительный метод экземпляра
+ def boast(self):
+ for power in self.superpowers:
+ print("Я обладаю силой '{pow}'!".format(pow=power))
+
-# Инициализация экземпляра класса
-i = Human(name="Иван")
-print(i.say("привет")) # Выводит: «Иван: привет»
+if __name__ == '__main__':
+ sup = Superhero(name="Тик")
-j = Human("Пётр")
-print(j.say("Привет")) # Выводит: «Пётр: привет»
+ # Проверка типа экземпляра
+ if isinstance(sup, Human):
+ print('Я человек')
+ if type(sup) is Superhero:
+ print('Я супергерой')
-# Вызов метода класса
-i.get_species() #=> "H. sapiens"
+ # Получить порядок поиска разрешения метода (MRO),
+ # используемый как getattr(), так и super()
+ # Этот атрибут является динамическим и может быть обновлен
+ print(Superhero.__mro__) # => (<class '__main__.Superhero'>,
+ # => <class 'human.Human'>, <class 'object'>)
-# Изменение разделяемого атрибута
-Human.species = "H. neanderthalensis"
-i.get_species() #=> "H. neanderthalensis"
-j.get_species() #=> "H. neanderthalensis"
+ # Вызывает родительский метод, но использует свой собственный атрибут класса
+ print(sup.get_species()) # => Сверхчеловек
-# Вызов статического метода
-Human.grunt() #=> "*grunt*"
+ # Вызов переопределенного метода
+ print(sup.sing()) # => Бам, бам, БАМ!
+
+ # Вызывает метод из Human
+ sup.say('Ложка') # => Тик: Ложка
+
+ # Метод вызова, существующий только в Superhero
+ sup.boast() # => Я обладаю силой 'сверхсила'!
+ # => Я обладаю силой 'пуленепробиваемость'!
+
+ # Атрибут унаследованного класса
+ sup.age = 31
+ print(sup.age) # => 31
+
+ # Атрибут, который существует только в Superhero
+ print('Достоин ли я Оскара? ' + str(sup.movie))
####################################################
-## 6. Модули
+## 6.2 Множественное наследование
####################################################
-# Вы можете импортировать модули
-import math
-print(math.sqrt(16)) #=> 4
+# Eще одно определение класса
+# bat.py
+class Bat:
-# Вы можете импортировать отдельные функции модуля
-from math import ceil, floor
-print(ceil(3.7)) #=> 4.0
-print(floor(3.7)) #=> 3.0
+ species = 'Летучая мышь'
-# Можете импортировать все функции модуля.
-# (Хотя это и не рекомендуется)
-from math import *
+ def __init__(self, can_fly=True):
+ self.fly = can_fly
-# Можете сокращать имена модулей
-import math as m
-math.sqrt(16) == m.sqrt(16) #=> True
-# Вы также можете убедиться, что функции эквивалентны
-from math import sqrt
-math.sqrt == m.sqrt == sqrt # => True
+ # В этом классе также есть метод say
+ def say(self, msg):
+ msg = '... ... ...'
+ return msg
-# Модули в Python — это обычные Python-файлы. Вы
-# можете писать свои модули и импортировать их. Название
-# модуля совпадает с названием файла.
+ # И свой метод тоже
+ def sonar(self):
+ return '))) ... ((('
+
+if __name__ == '__main__':
+ b = Bat()
+ print(b.say('привет'))
+ print(b.fly)
+
+
+# И еще одно определение класса, унаследованное от Superhero и Bat
+# superhero.py
+from superhero import Superhero
+from bat import Bat
+
+# Определите Batman как дочерний класс, унаследованный от Superhero и Bat
+class Batman(Superhero, Bat):
+
+ def __init__(self, *args, **kwargs):
+ # Обычно для наследования атрибутов необходимо вызывать super:
+ # super(Batman, self).__init__(*args, **kwargs)
+ # Однако здесь мы имеем дело с множественным наследованием, а super()
+ # работает только со следующим базовым классом в списке MRO.
+ # Поэтому вместо этого мы вызываем __init__ для всех родителей.
+ # Использование *args и **kwargs обеспечивает чистый способ передачи
+ # аргументов, когда каждый родитель "очищает слой луковицы".
+ Superhero.__init__(self, 'анонимный', movie=True,
+ superpowers=['Богатый'], *args, **kwargs)
+ Bat.__init__(self, *args, can_fly=False, **kwargs)
+ # переопределить значение атрибута name
+ self.name = 'Грустный Бен Аффлек'
+
+ def sing(self):
+ return 'на на на на на бэтмен!'
+
+
+if __name__ == '__main__':
+ sup = Batman()
+
+ # Получить порядок поиска разрешения метода (MRO),
+ # используемый как getattr(), так и super()
+ # Этот атрибут является динамическим и может быть обновлен
+ print(Batman.__mro__) # => (<class '__main__.Batman'>,
+ # => <class 'superhero.Superhero'>,
+ # => <class 'human.Human'>,
+ # => <class 'bat.Bat'>, <class 'object'>)
+
+ # Вызывает родительский метод, но использует свой собственный атрибут класса
+ print(sup.get_species()) # => Сверхчеловек
+
+ # Вызов переопределенного метода
+ print(sup.sing()) # => на на на на на бэтмен!
+
+ # Вызывает метод из Human, потому что порядок наследования имеет значение
+ sup.say('Я согласен') # => Грустный Бен Аффлек: Я согласен
+
+ # Вызов метода, существующий только во втором родителе
+ print(sup.sonar()) # => ))) ... (((
+
+ # Атрибут унаследованного класса
+ sup.age = 100
+ print(sup.age) # => 100
+
+ # Унаследованный атрибут от второго родителя,
+ # значение по умолчанию которого было переопределено.
+ print('Могу ли я летать? ' + str(sup.fly)) # => Могу ли я летать? False
-# Вы можете узнать, какие функции и атрибуты определены
-# в модуле
-import math
-dir(math)
####################################################
## 7. Дополнительно
@@ -577,28 +988,30 @@ def double_numbers(iterable):
for i in iterable:
yield i + i
-# Генератор создаёт значения на лету.
-# Он не возвращает все значения разом, а создаёт каждое из них при каждой
-# итерации. Это значит, что значения больше 15 в double_numbers
-# обработаны не будут.
-# Обратите внимание: xrange — это генератор, который делает то же, что и range.
-# Создание списка чисел от 1 до 900000000 требует много места и времени.
-# xrange создаёт объект генератора, а не список сразу, как это делает range.
-# Если нам нужно имя переменной, совпадающее с ключевым словом Python,
-# мы используем подчёркивание в конце
-xrange_ = xrange(1, 900000000)
-
-# Будет удваивать все числа, пока результат не превысит 30
-for i in double_numbers(xrange_):
+# Генераторы эффективны с точки зрения памяти, потому что они загружают только данные,
+# необходимые для обработки следующего значения в итерации.
+# Это позволяет им выполнять операции с недопустимо большими диапазонами значений.
+# ПРИМЕЧАНИЕ: "range" заменяет "xrange" в Python 3.
+for i in double_numbers(range(1, 900000000)): # "range" - генератор.
print(i)
if i >= 30:
break
+# Так же, как вы можете создать интерпретации списков, вы можете создать и
+# интерпретации генераторов.
+values = (-x for x in [1,2,3,4,5])
+for x in values:
+ print(x) # Выводит -1 -2 -3 -4 -5
+
+# Вы также можете преобразовать интерпретацию генератора непосредственно в список.
+values = (-x for x in [1,2,3,4,5])
+gen_to_list = list(values)
+print(gen_to_list) # => [-1, -2, -3, -4, -5]
+
# Декораторы
-# В этом примере beg оборачивает say
-# Метод beg вызовет say. Если say_please равно True,
-# он изменит возвращаемое сообщение
+# В этом примере "beg" оборачивает "say".
+# Если say_please равно True, он изменит возвращаемое сообщение.
from functools import wraps
@@ -607,7 +1020,7 @@ def beg(target_function):
def wrapper(*args, **kwargs):
msg, say_please = target_function(*args, **kwargs)
if say_please:
- return "{} {}".format(msg, " Пожалуйста! У меня нет денег :(")
+ return "{} {}".format(msg, "Пожалуйста! У меня нет денег :(")
return msg
return wrapper
@@ -619,8 +1032,8 @@ def say(say_please=False):
return msg, say_please
-print(say()) # Вы не купите мне пива?
-print(say(say_please=True)) # Вы не купите мне пива? Пожалуйста! У меня нет денег :(
+print(say()) # Вы не купите мне пива?
+print(say(say_please=True)) # Вы не купите мне пива? Пожалуйста! У меня нет денег :(
```
@@ -628,16 +1041,18 @@ print(say(say_please=True)) # Вы не купите мне пива? Пожал
### Бесплатные онлайн-материалы
-* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/)
-* [Dive Into Python](http://www.diveintopython.net/)
-* [Официальная документация](http://docs.python.org/2.6/)
+* [Automate the Boring Stuff with Python](https://automatetheboringstuff.com)
+* [Ideas for Python Projects](http://pythonpracticeprojects.com)
+* [Официальная документация](http://docs.python.org/3/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
-* [Python Module of the Week](http://pymotw.com/2/)
-* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182)
-
-### Платные
-
-* [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20)
-* [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20)
-* [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20)
+* [Python Course](http://www.python-course.eu/index.php)
+* [First Steps With Python](https://realpython.com/learn/python-first-steps/)
+* [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python)
+* [30 Python Language Features and Tricks You May Not Know About](http://sahandsaba.com/thirty-python-language-features-and-tricks-you-may-not-know.html)
+* [Official Style Guide for Python](https://www.python.org/dev/peps/pep-0008/)
+* [Python 3 Computer Science Circles](http://cscircles.cemc.uwaterloo.ca/)
+* [Dive Into Python 3](http://www.diveintopython3.net/index.html)
+* [A Crash Course in Python for Scientists](http://nbviewer.jupyter.org/gist/anonymous/5924718)
+* [Python Tutorial for Intermediates](https://pythonbasics.org/)
+* [Build a Desktop App with Python](https://pythonpyqt.com/)
diff --git a/ru-ru/python3-ru.html.markdown b/ru-ru/pythonlegacy-ru.html.markdown
index 2b6b59a7..ead2af3d 100644
--- a/ru-ru/python3-ru.html.markdown
+++ b/ru-ru/pythonlegacy-ru.html.markdown
@@ -1,23 +1,23 @@
---
-language: python3
+language: Python 2 (legacy)
lang: ru-ru
contributors:
- ["Louie Dinh", "http://ldinh.ca"]
- - ["Steven Basart", "http://github.com/xksteven"]
translators:
+ - ["Yury Timofeev", "http://twitter.com/gagar1n"]
- ["Andre Polykanine", "https://github.com/Oire"]
-filename: learnpython3-ru.py
+filename: learnpythonlegacy-ru.py
---
Язык Python был создан Гвидо ван Россумом в начале 90-х. Сейчас это один из
самых популярных языков. Я влюбился в Python за понятный и доходчивый синтаксис — это
-почти что исполняемый псевдокод.
+почти исполняемый псевдокод.
С благодарностью жду ваших отзывов: [@louiedinh](http://twitter.com/louiedinh)
или louiedinh [at] [почтовый сервис Google]
-Замечание: Эта статья относится только к Python 3.
-Если вы хотите изучить Python 2.7, обратитесь к другой статье.
+Замечание: Эта статья относится к Python 2.7, но должно работать и в других версиях Python 2.x.
+Чтобы изучить Python 3.x, обратитесь к статье по Python 3.
```python
# Однострочные комментарии начинаются с символа решётки.
@@ -37,9 +37,16 @@ filename: learnpython3-ru.py
1 + 1 #=> 2
8 - 1 #=> 7
10 * 2 #=> 20
+35 / 5 #=> 7
-# Кроме деления, которое по умолчанию возвращает число с плавающей запятой
-35 / 5 # => 7.0
+# А вот деление немного сложнее. В этом случае происходит деление
+# целых чисел, и результат автоматически округляется в меньшую сторону.
+5 / 2 #=> 2
+
+# Чтобы делить правильно, сначала нужно немного узнать о числах
+# с плавающей запятой.
+2.0 # Это число с плавающей запятой
+11.0 / 4.0 #=> 2.75 Вооот... Так гораздо лучше
# Результат целочисленного деления округляется в меньшую сторону
# как для положительных, так и для отрицательных чисел.
@@ -48,10 +55,6 @@ filename: learnpython3-ru.py
-5 // 3 # => -2
-5.0 // 3.0 # => -2.0
-# Когда вы используете числа с плавающей запятой,
-# результатом будет также число с плавающей запятой
-3 * 2.0 # => 6.0
-
# Остаток от деления
7 % 3 # => 1
@@ -61,14 +64,6 @@ filename: learnpython3-ru.py
# Приоритет операций указывается скобками
(1 + 3) * 2 #=> 8
-# Для логических (булевых) значений существует отдельный примитивный тип
-True
-False
-
-# Для отрицания используется ключевое слово not
-not True #=> False
-not False #=> True
-
# Логические операторы
# Обратите внимание: ключевые слова «and» и «or» чувствительны к регистру букв
True and False #=> False
@@ -81,6 +76,10 @@ False or True #=> True
2 == True #=> False
1 == True #=> True
+# Для отрицания используется ключевое слово not
+not True #=> False
+not False #=> True
+
# Равенство — это ==
1 == 1 #=> True
2 == 1 #=> False
@@ -95,7 +94,7 @@ False or True #=> True
2 <= 2 #=> True
2 >= 2 #=> True
-# Сравнения могут быть записаны цепочкой:
+# Сравнения могут быть записаны цепочкой!
1 < 2 < 3 #=> True
2 < 3 < 2 #=> False
@@ -103,67 +102,75 @@ False or True #=> True
"Это строка."
'Это тоже строка.'
-# И строки тоже могут складываться! Хотя лучше не злоупотребляйте этим.
+# И строки тоже можно складывать!
"Привет " + "мир!" #=> "Привет мир!"
+# ... или умножать
+"Привет" * 3 # => "ПриветПриветПривет"
+
# Со строкой можно работать, как со списком символов
"Это строка"[0] #=> 'Э'
-# Метод format используется для форматирования строк:
+# Символ % используется для форматирования строк, например:
+"%s могут быть %s" % ("строки", "интерполированы")
+
+# Новый способ форматирования строк — использование метода format.
+# Это предпочитаемый способ.
"{0} могут быть {1}".format("строки", "форматированы")
-# Вы можете повторять аргументы форматирования, чтобы меньше печатать.
-"Ехал {0} через реку, видит {0} - в реке {1}! Сунул {0} руку в реку, {1} за руку греку цап!".format("грека", "рак")
-#=> "Ехал грека через реку, видит грека - в реке рак! Сунул грека руку в реку, рак за руку греку цап!"
# Если вы не хотите считать, можете использовать ключевые слова.
"{name} хочет есть {food}".format(name="Боб", food="лазанью")
-# Если ваш код на Python 3 нужно запускать также и под Python 2.5 и ниже,
-# вы также можете использовать старый способ форматирования:
-"%s можно %s %s способом" % ("строки", "интерполировать", "старым")
-
# None является объектом
None #=> None
-# Не используйте оператор равенства '==' для сравнения
-# объектов с None. Используйте для этого 'is'
+# Не используйте оператор равенства '=='' для сравнения
+# объектов с None. Используйте для этого «is»
"etc" is None #=> False
None is None #=> True
-# Оператор «is» проверяет идентичность объектов. Он не
+# Оператор 'is' проверяет идентичность объектов. Он не
# очень полезен при работе с примитивными типами, но
# зато просто незаменим при работе с объектами.
-# None, 0 и пустые строки/списки/словари приводятся к False.
+# None, 0 и пустые строки/списки равны False.
# Все остальные значения равны True
-bool(0) # => False
-bool("") # => False
-bool([]) #=> False
-bool({}) #=> False
+0 == False #=> True
+"" == False #=> True
####################################################
## 2. Переменные и коллекции
####################################################
-# В Python есть функция Print
-print("Я Python. Приятно познакомиться!")
+# В Python есть оператор print, доступный в версиях 2.x, но удалённый в версии 3
+print "Я Python. Приятно познакомиться!"
+# В Python также есть функция print(), доступная в версиях 2.7 и 3,
+# Но для версии 2.7 нужно добавить следующий импорт модуля (раскомментируйте)):
+# from __future__ import print_function
+print("Я тоже Python! ")
# Объявлять переменные перед инициализацией не нужно.
-# По соглашению используется нижний_регистр_с_подчёркиваниями
-some_var = 5
+some_var = 5 # По соглашению используется нижний_регистр_с_подчёркиваниями
some_var #=> 5
# При попытке доступа к неинициализированной переменной
# выбрасывается исключение.
-# Об исключениях см. раздел «Поток управления и итерируемые объекты».
-some_unknown_var # Выбрасывает ошибку именования
+# См. раздел «Поток управления» для информации об исключениях.
+some_other_var # Выбрасывает ошибку именования
+
+# if может быть использован как выражение
+"yahoo!" if 3 > 2 else 2 #=> "yahoo!"
# Списки хранят последовательности
li = []
# Можно сразу начать с заполненного списка
other_li = [4, 5, 6]
+# строка разделена в список
+a="adambard"
+list(a) #=> ['a','d','a','m','b','a','r','d']
+
# Объекты добавляются в конец списка методом append
li.append(1) # [1]
li.append(2) # [1, 2]
@@ -176,6 +183,10 @@ li.append(3) # [1, 2, 4, 3].
# Обращайтесь со списком, как с обычным массивом
li[0] #=> 1
+# Присваивайте новые значения уже инициализированным индексам с помощью =
+li[0] = 42
+li[0] # => 42
+li[0] = 1 # Обратите внимание: возвращаемся на исходное значение
# Обратимся к последнему элементу
li[-1] #=> 3
@@ -197,11 +208,11 @@ li[::-1] # => [3, 4, 2, 1]
# li[начало:конец:шаг]
# Удаляем произвольные элементы из списка оператором del
-del li[2] # [1, 2, 3]
+del li[2] # li теперь [1, 2, 3]
# Вы можете складывать, или, как ещё говорят, конкатенировать списки
-# Обратите внимание: значения li и other_li при этом не изменились.
li + other_li #=> [1, 2, 3, 4, 5, 6] — Замечание: li и other_li не изменяются
+# Обратите внимание: значения li и other_li при этом не изменились.
# Объединять списки можно методом extend
li.extend(other_li) # Теперь li содержит [1, 2, 3, 4, 5, 6]
@@ -231,7 +242,6 @@ d, e, f = 4, 5, 6
# Обратите внимание, как легко поменять местами значения двух переменных
e, d = d, e # теперь d == 5, а e == 4
-
# Словари содержат ассоциативные массивы
empty_dict = {}
# Вот так описывается предзаполненный словарь
@@ -241,17 +251,13 @@ filled_dict = {"one": 1, "two": 2, "three": 3}
# что индекс — у словарей он называется ключом — не обязан быть числом
filled_dict["one"] #=> 1
-# Все ключи в виде списка получаются с помощью метода keys().
-# Его вызов нужно обернуть в list(), так как обратно мы получаем
-# итерируемый объект, о которых поговорим позднее.
-list(filled_dict.keys()) # => ["three", "two", "one"]
+# Можно получить все ключи в виде списка с помощью метода keys
+filled_dict.keys() #=> ["three", "two", "one"]
# Замечание: сохранение порядка ключей в словаре не гарантируется
# Ваши результаты могут не совпадать с этими.
-# Все значения в виде списка можно получить с помощью values().
-# И снова нам нужно обернуть вызов в list(), чтобы превратить
-# итерируемый объект в список.
-list(filled_dict.values()) # => [3, 2, 1]
+# Можно получить и все значения в виде списка, используйте метод values
+filled_dict.values() #=> [3, 2, 1]
# То же самое замечание насчёт порядка ключей справедливо и здесь
# При помощи оператора in можно проверять ключи на вхождение в словарь
@@ -268,27 +274,28 @@ filled_dict.get("four") #=> None
# возвращено при отсутствии указанного ключа
filled_dict.get("one", 4) #=> 1
filled_dict.get("four", 4) #=> 4
+# Обратите внимание, что filled_dict.get("four") всё ещё => None
+# (get не устанавливает значение элемента словаря)
-# Метод setdefault вставляет пару ключ-значение, только если такого ключа нет
+# Присваивайте значение ключам так же, как и в списках
+filled_dict["four"] = 4 # теперь filled_dict["four"] => 4
+
+# Метод setdefault() вставляет пару ключ-значение, только если такого ключа нет
filled_dict.setdefault("five", 5) #filled_dict["five"] возвращает 5
filled_dict.setdefault("five", 6) #filled_dict["five"] по-прежнему возвращает 5
-# Добавление элементов в словарь
-filled_dict.update({"four":4}) #=> {"one": 1, "two": 2, "three": 3, "four": 4}
-#filled_dict["four"] = 4 # Другой способ добавления элементов
-
-# Удаляйте ключи из словаря с помощью оператора del
-del filled_dict["one"] # Удаляет ключ «one» из словаря
-
# Множества содержат... ну, в общем, множества
+# (которые похожи на списки, только в них не может быть дублирующихся элементов)
empty_set = set()
-# Инициализация множества набором значений.
-# Да, оно выглядит примерно как словарь… ну извините, так уж вышло.
-filled_set = {1, 2, 2, 3, 4} # => {1, 2, 3, 4}
+# Инициализация множества набором значений
+some_set = set([1,2,2,3,4]) # some_set теперь равно set([1, 2, 3, 4])
+
+# Порядок сортировки не гарантируется, хотя иногда они выглядят отсортированными
+another_set = set([4, 3, 2, 2, 1]) # another_set теперь set([1, 2, 3, 4])
-# Множеству можно назначать новую переменную
-filled_set = some_set
+# Начиная с Python 2.7, вы можете использовать {}, чтобы объявить множество
+filled_set = {1, 2, 2, 3, 4} # => {1, 2, 3, 4}
# Добавление новых элементов в множество
filled_set.add(5) # filled_set равно {1, 2, 3, 4, 5}
@@ -309,7 +316,7 @@ filled_set | other_set #=> {1, 2, 3, 4, 5, 6}
####################################################
-## 3. Поток управления и итерируемые объекты
+## 3. Поток управления
####################################################
# Для начала заведём переменную
@@ -325,13 +332,17 @@ else: # Это тоже необязательно.
print("some_var равно 10.")
-# Циклы For проходят по спискам. Результат:
- # собака — это млекопитающее
- # кошка — это млекопитающее
- # мышь — это млекопитающее
+"""
+Циклы For проходят по спискам
+
+Результат:
+ собака — это млекопитающее
+ кошка — это млекопитающее
+ мышь — это млекопитающее
+"""
for animal in ["собака", "кошка", "мышь"]:
- # Можете использовать format() для интерполяции форматированных строк
- print("{} — это млекопитающее".format(animal))
+ # Можете использовать оператор % для интерполяции форматированных строк
+ print("%s — это млекопитающее" % animal)
"""
«range(число)» возвращает список чисел
@@ -359,6 +370,8 @@ while x < 4:
x += 1 # Краткая запись для x = x + 1
# Обрабатывайте исключения блоками try/except
+
+# Работает в Python 2.6 и выше:
try:
# Чтобы выбросить ошибку, используется raise
raise IndexError("Это ошибка индекса")
@@ -371,37 +384,6 @@ except (TypeError, NameError):
else: # Необязательное выражение. Должно следовать за последним блоком except
print("Всё хорошо!") # Выполнится, только если не было никаких исключений
-# Python предоставляет фундаментальную абстракцию,
-# которая называется итерируемым объектом (an iterable).
-# Итерируемый объект — это объект, который воспринимается как последовательность.
-# Объект, который возвратила функция range(), итерируемый.
-filled_dict = {"one": 1, "two": 2, "three": 3}
-our_iterable = filled_dict.keys()
-print(our_iterable) #=> range(1,10). Это объект, реализующий интерфейс iterable
-
-# Мы можем проходить по нему циклом.
-for i in our_iterable:
- print(i) # Выводит one, two, three
-
-# Но мы не можем обращаться к элементу по индексу.
-our_iterable[1] # Выбрасывает ошибку типа
-
-# Итерируемый объект знает, как создавать итератор.
-our_iterator = iter(our_iterable)
-
-# Итератор может запоминать состояние при проходе по объекту.
-# Мы получаем следующий объект, вызывая функцию __next__.
-our_iterator.__next__() #=> "one"
-
-# Он сохраняет состояние при вызове __next__.
-our_iterator.__next__() #=> "two"
-our_iterator.__next__() #=> "three"
-
-# Возвратив все данные, итератор выбрасывает исключение StopIterator
-our_iterator.__next__() # Выбрасывает исключение остановки итератора
-
-# Вы можете получить сразу все элементы итератора, вызвав на нём функцию list().
-list(filled_dict.keys()) #=> Возвращает ["one", "two", "three"]
####################################################
@@ -419,7 +401,8 @@ add(5, 6) #=> выводит «x равен 5, а y равен 6» и возвр
# Другой способ вызова функции — вызов с именованными аргументами
add(y=6, x=5) # Именованные аргументы можно указывать в любом порядке.
-# Вы можете определить функцию, принимающую переменное число аргументов
+# Вы можете определить функцию, принимающую переменное число аргументов,
+# которые будут интерпретированы как кортеж, если вы не используете *
def varargs(*args):
return args
@@ -427,7 +410,8 @@ varargs(1, 2, 3) #=> (1,2,3)
# А также можете определить функцию, принимающую переменное число
-# именованных аргументов
+# именованных аргументов, которые будут интерпретированы как словарь,
+# если вы не используете **
def keyword_args(**kwargs):
return kwargs
@@ -452,6 +436,14 @@ all_the_args(*args) # эквивалентно foo(1, 2, 3, 4)
all_the_args(**kwargs) # эквивалентно foo(a=3, b=4)
all_the_args(*args, **kwargs) # эквивалентно foo(1, 2, 3, 4, a=3, b=4)
+# вы можете передавать переменное число позиционных или именованных аргументов
+# другим функциям, которые их принимают, распаковывая их с помощью
+# * или ** соответственно
+def pass_all_the_args(*args, **kwargs):
+ all_the_args(*args, **kwargs)
+ print varargs(*args)
+ print keyword_args(**kwargs)
+
# Область определения функций
x = 5
@@ -510,7 +502,7 @@ class Human(object):
# Метод экземпляра. Все методы принимают self в качестве первого аргумента
def say(self, msg):
- return "{name}: {message}".format(name=self.name, message=msg)
+ return "%s: %s" % (self.name, msg)
# Метод класса разделяется между всеми экземплярами
# Они вызываются с указыванием вызывающего класса в качестве первого аргумента
@@ -563,6 +555,9 @@ from math import *
# Можете сокращать имена модулей
import math as m
math.sqrt(16) == m.sqrt(16) #=> True
+# Вы также можете убедиться, что функции эквивалентны
+from math import sqrt
+math.sqrt == m.sqrt == sqrt # => True
# Модули в Python — это обычные Python-файлы. Вы
# можете писать свои модули и импортировать их. Название
@@ -586,14 +581,15 @@ def double_numbers(iterable):
# Он не возвращает все значения разом, а создаёт каждое из них при каждой
# итерации. Это значит, что значения больше 15 в double_numbers
# обработаны не будут.
-# Обратите внимание: range — это тоже генератор.
+# Обратите внимание: xrange — это генератор, который делает то же, что и range.
# Создание списка чисел от 1 до 900000000 требует много места и времени.
+# xrange создаёт объект генератора, а не список сразу, как это делает range.
# Если нам нужно имя переменной, совпадающее с ключевым словом Python,
# мы используем подчёркивание в конце
-range_ = range(1, 900000000)
+xrange_ = xrange(1, 900000000)
# Будет удваивать все числа, пока результат не превысит 30
-for i in double_numbers(range_):
+for i in double_numbers(xrange_):
print(i)
if i >= 30:
break
@@ -634,10 +630,9 @@ print(say(say_please=True)) # Вы не купите мне пива? Пожал
* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/)
* [Dive Into Python](http://www.diveintopython.net/)
-* [Ideas for Python Projects](http://pythonpracticeprojects.com)
-* [Официальная документация](http://docs.python.org/3/)
+* [Официальная документация](http://docs.python.org/2.6/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
-* [Python Module of the Week](http://pymotw.com/3/)
+* [Python Module of the Week](http://pymotw.com/2/)
* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182)
### Платные
diff --git a/ru-ru/ruby-ru.html.markdown b/ru-ru/ruby-ru.html.markdown
index 69b5fb46..8b263be6 100644
--- a/ru-ru/ruby-ru.html.markdown
+++ b/ru-ru/ruby-ru.html.markdown
@@ -10,6 +10,7 @@ contributors:
- ["Nick LaMuro", "https://github.com/NickLaMuro"]
translators:
- ["Alexey Makarov", "https://github.com/Anakros"]
+ - ["Vasiliy Petrov", "https://github.com/Saugardas"]
---
```ruby
@@ -35,6 +36,13 @@ translators:
8 - 1 #=> 7
10 * 2 #=> 20
35 / 5 #=> 7
+2**5 #=> 32
+5 % 3 #=> 2
+
+# Побитовые операторы
+3 & 5 #=> 1
+3 | 5 #=> 7
+3 ^ 5 #=> 6
# Арифметика -- это синтаксический сахар
# над вызовом метода для объекта
@@ -57,8 +65,6 @@ false.class #=> FalseClass
# Операция неравенства
1 != 1 #=> false
2 != 1 #=> true
-!true #=> false
-!false #=> true
# nil -- имеет такое же логическое значение, как и false
@@ -72,6 +78,26 @@ false.class #=> FalseClass
2 <= 2 #=> true
2 >= 2 #=> true
+# Оператор сравнения <=>
+1 <=> 10 #=> -1
+10 <=> 1 #=> 1
+1 <=> 1 #=> 0
+
+# Булевы операторы
+true && false #=> false
+true || false #=> true
+!true #=> false
+
+# Существуют альтернативные версии логических операторов с гораздо меньшим
+# приоритетом. Они используются для связывания операций, пока одна из них
+# не вернёт false или true
+
+# `do_something_else` будет вызван если `do_something` вернёт истинное значение
+do_something() and do_something_else()
+# `log_error` будет вызван если `do_something` вернёт (nil/false)
+do_something() or log_error()
+
+
# Строки -- это объекты
'Я строка'.class #=> String
@@ -82,6 +108,16 @@ placeholder = "использовать интерполяцию строк"
#=> "Я могу использовать интерполяцию строк,
# когда создаю строку с двойными кавычками"
+# Конкатенация строк
+'hello ' + 'world' #=> "hello world"
+'hello ' + 3 #=> TypeError: can't convert Fixnum into String
+'hello ' + 3.to_s #=> "hello 3"
+
+# Умножение строк
+'hello ' * 3 #=> "hello hello hello "
+
+# Добавление к строке
+'hello' << ' world' #=> "hello world"
# печатать в стандартный вывод
puts "Я печатаюсь!"
@@ -134,6 +170,7 @@ array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
# Значение в массиве можно получить по индексу с левой границы
array[0] #=> 1
+array.first #=> 1
array[12] #=> nil
# Как и арифметика, доступ к значению в массиве
@@ -143,15 +180,26 @@ array.[] 12 #=> nil
# Также, можно получить по индексу с правой границы
array[-1] #=> 5
+array.last #=> 5
-# С заданными левой и правой границами индексов
-array[2, 4] #=> [3, 4, 5]
+# Задавая индекс и количество элементов
+array[0,2] #=> [1, 2]
+array[0,999] #=> [1, 2, 3, 4, 5]
# Или с использованием диапазона значений
array[1..3] #=> [2, 3, 4]
+# Перестановка элементов в обратном порядке
+a = [1, 2, 3]
+a.reverse #=> [3, 2, 1]
+
# Вот так можно добавить значение в массив
array << 6 #=> [1, 2, 3, 4, 5, 6]
+# Или так
+array.push(6) #=> [1, 2, 3, 4, 5, 6]
+
+# Проверка включения элемента в массив
+array.include?(1) #=> true
# Хэши -- это массив пар "ключ => значение".
# Хэши объявляются с использованием фигурных скобок:
@@ -174,19 +222,33 @@ new_hash = { defcon: 3, action: true}
new_hash.keys #=> [:defcon, :action]
+# Проверка существования ключа и значения в хеше
+new_hash.key?(:defcon) #=> true
+new_hash.value?(3) #=> true
+
# Массивы и Хэши -- перечисляемые типы данных
# У них есть много полезных методов, например: each, map, count и другие
# Управление ходом выполнения (Управляющие структуры)
+# Условия
if true
- "Если истина"
+ 'Если истина'
elsif false
- "Иначе, если ложь (опционально)"
+ 'Иначе, если ложь (опционально)'
else
- "Во всех других случаях"
+ 'Во всех других случаях (тоже опционально)'
end
+# Если условие контролирует выполнение не блока кода, а единственного выражения,
+# можно использовать постфиксную запись условного оператора
+warnings = ['Отсутствует отчество', 'Слишком короткий адрес']
+puts("Обратите внимание:\n" + warnings.join("\n")) if !warnings.empty?
+
+# Иногда условие лучше звучит с `unless`, чем с `if`
+puts("Обратите внимание:\n" + warnings.join("\n")) unless warnings.empty?
+
+# Циклы
for counter in 1..5
puts "итерация #{counter}"
end
@@ -220,7 +282,7 @@ end
#=> итерация 5
# Вы также можете ограничивать блоки фигурными скобками:
-(1..5).each {|counter| puts "итерация #{counter}"}
+(1..5).each { |counter| puts "итерация #{counter}" }
# Содержимое структурных данных также можно перебирать используя "each":
array.each do |element|
@@ -230,6 +292,21 @@ hash.each do |key, value|
puts "#{key} -- это #{value}"
end
+# Если вам нужен индекс вы можете использовать "each_with_index"
+# В этом случае индекс будет начинаться с 0
+array.each_with_index do |element, index|
+ puts "#{element} is number #{index} in the array"
+end
+
+# Если индекс должен начинаться с произвольного значения,
+# используйте "each.with_index"
+[:q, :w, :e].each.with_index(100) do |element, index|
+ puts "#{element} -> #{index}"
+end
+#=> :q -> 100
+#=> :w -> 101
+#=> :e -> 102
+
counter = 1
while counter <= 5 do
puts "итерация #{counter}"
@@ -241,22 +318,65 @@ end
#=> итерация 4
#=> итерация 5
+# Существует большое количество других полезных функций,
+# например "map", "reduce", "inject", и так далее. Например, "map"
+# выполняет связанный с ним блок для каждого элемента перечисляемого объекта,
+# возвращая массив результатов.
+array = [1, 2, 3, 4, 5]
+doubled = array.map do |element|
+ element * 2
+end
+puts doubled
+#=> [2, 4, 6, 8, 10]
+puts array
+#=> [1, 2, 3, 4, 5]
+
grade = 'B'
case grade
when 'A'
- puts "Так держать, детка!"
+ puts 'Так держать, детка!'
when 'B'
- puts "Тебе повезёт в следующий раз"
+ puts 'Тебе повезёт в следующий раз'
when 'C'
- puts "Ты можешь сделать лучше"
+ puts 'Ты можешь сделать лучше'
when 'D'
- puts "Выскоблил последнее"
+ puts 'Выскоблил последнее'
when 'F'
- puts "Ты провалился!"
+ puts 'Ты провалился!'
else
- puts "Альтернативная система оценок, да?"
+ puts 'Альтернативная система оценок, да?'
end
+#=> 'Тебе повезёт в следующий раз'
+
+# в when также можно использовать диапазоны
+grade = 82
+case grade
+when 90..100
+ puts 'Ура!'
+when 80...90
+ puts 'Хорошая работа!'
+else
+ puts 'Вы не справились!'
+end
+#=> 'Хорошая работа!'
+
+# Обработка исключений
+begin
+ # здесь код, который может вызвать исключение
+ raise NoMemoryError, 'У вас закончилась память.'
+rescue NoMemoryError => exception_variable
+ puts 'Был вызван NoMemoryError', exception_variable
+rescue RuntimeError => other_exception_variable
+ puts 'Был вызван RuntimeError'
+else
+ puts 'Этот код будет выполнятся, если исключения не были вызваны'
+ensure
+ puts 'Этот код выполняется всегда'
+end
+#=> Был вызван NoMemoryError
+#=> У вас закончилась память.
+#=> Этот код выполняется всегда
# Функции
@@ -298,6 +418,43 @@ surround { puts 'hello world' }
# }
+# Вы можете передать блок методу
+# "&" отмечает ссылку на переданный блок
+def guests(&block)
+ block.call 'some_argument'
+end
+
+# Чтобы метод принимал произвольное количество аргументов, спереди
+# одного из параметров ставится префикс "*"
+def method(first, *rest)
+ p rest
+end
+method(1, 2, 3, 4) #=> [2, 3, 4]
+
+# Если метод возвращает массив. можно использовать множественное присваивание
+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.upcase #=> "DUNDER MIFFLIN"
+company_name #=> "Dunder Mifflin"
+company_name.upcase! # Изменяем зачение company_name!
+company_name #=> "DUNDER MIFFLIN"
+
+
# Определение класса с помощью ключевого слова "class"
class Human
@@ -323,6 +480,13 @@ class Human
@name
end
+ # Тоже самое можно определить с помощью attr_accessor
+ attr_accessor :name
+
+ # Также можно создать методы только для записи или чтения
+ attr_reader :name
+ attr_writer :name
+
# Метод класса определяется с ключевым словом "self",
# чтобы можно было отличить его от метода экземпляра класса.
# Он может быть вызван только на уровне класса, но не экземпляра.
diff --git a/ru-ru/rust-ru.html.markdown b/ru-ru/rust-ru.html.markdown
new file mode 100644
index 00000000..9293a40e
--- /dev/null
+++ b/ru-ru/rust-ru.html.markdown
@@ -0,0 +1,313 @@
+---
+language: rust
+
+filename: learnrust-ru.rs
+contributors:
+ - ["P1start", "http://p1start.github.io/"]
+translators:
+ - ["Anatolii Kosorukov", "https://github.com/java1cprog"]
+ - ["Vasily Starostin", "https://github.com/Basil22"]
+lang: ru-ru
+
+---
+
+Язык Rust разработан в Mozilla Research. Он сочетает низкоуровневую производительность с удобством языка высокого уровня и одновременно гарантирует безопасность памяти.
+
+Он достигает этих целей без сборщика мусора или сложной среды выполнения, что позволяет использовать библиотеки Rust как прямую замену
+C-библиотек. И наоборот, Rust умеет использовать готовые С-библиотеки как есть, без накладных расходов.
+
+Первый выпуск Rust, 0.1, произошел в январе 2012 года. В течение 3 лет развитие продвигалось настолько быстро, что язык серьезно менялся без сохранения совместимости. Это дало возможность обкатать и отполировать синтаксис и возможности языка.
+
+15 мая 2015 года был выпущен Rust 1.0 с полной гарантией обратной совместимости. Сборка поставляется в трех вариантах: стабильная версия, бета-версия, ночная версия. Все нововведения языка сперва обкатываются на ночной и бета-версиях, и только потом попадают в стабильную. Выход очередной версии происходит раз в 6 недель. В 2018 году вышло второе большое обновление языка, добавившее ему новых возможностей.
+
+Хотя 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 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;
+
+ // Перечисление с полями
+ // В отличие от C и C++ компилятор автоматически следит за тем,
+ // какой именно тип хранится в перечислении.
+ 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).
diff --git a/ru-ru/sql-ru.html.markdown b/ru-ru/sql-ru.html.markdown
new file mode 100644
index 00000000..7353a175
--- /dev/null
+++ b/ru-ru/sql-ru.html.markdown
@@ -0,0 +1,120 @@
+---
+language: SQL
+filename: learnsql-ru.sql
+contributors:
+ - ["Bob DuCharme", "http://bobdc.com/"]
+translators:
+ - ["Shaltaev", "https://github.com/shaltaev"]
+ - ["Andre Polykanine", "https://github.com/Menelion"]
+lang: ru-ru
+---
+
+Язык структурированных запросов (SQL) — это стандартный язык ISO для создания
+и работы с базами данных, хранящимися в наборе таблиц. Реализации обычно
+добавляют свои собственные расширения к языку;
+[Сравнение различных реализаций SQL](http://troels.arvin.dk/db/rdbms/) — хороший справочник по различиям в продуктах.
+
+Реализации обычно предоставляют приглашение командной строки, где вы можете
+вводить команды, описанные ниже, в интерактивном режиме, также есть способ
+выполнить серию таких команд, сохранённых в файле скрипта.
+(Результат того, что вы сделали с помощью интерактивного режима, является
+хорошим примером того, что не стандартизировано, — большинство реализаций SQL
+поддерживают ключевые слова QUIT, EXIT или оба).
+
+Некоторые команды ниже предполагают использование
+[демонстрационного образца базы данных сотрудников от MySQL](https://dev.mysql.com/doc/employee/en/), доступного на [Github](https://github.com/datacharmer/test_db).
+Следовательно, для повторения команд в локальном окружении он должен быть загружен.
+Файлы на github — это скрипты с командами, которые схожи с командами ниже,
+которые создают и манипулируют таблицами и данными о сотрудниках вымышленной
+компании. Синтаксис для запуска этих скриптов будет зависеть от используемой
+вами реализации SQL. Обычно используется утилита, запускаемая из командной
+строки в вашей операционной системе.
+
+```sql
+-- Комментарии начинаются с двух дефисов. Завершайте каждую команду
+-- точкой с запятой.
+
+-- SQL не учитывает регистр букв для ключевых слов. Примеры команд здесь
+-- следуют соглашению о написании в верхнем регистре, потому что
+-- это позволяет легче отличить их от имён баз, таблиц и колонок.
+
+-- Создание и удаление базы данных. Имена базы и таблицы чувствительны
+-- к регистру букв.
+CREATE DATABASE someDatabase;
+DROP DATABASE someDatabase;
+
+-- Список доступных баз.
+SHOW DATABASES;
+
+-- Выбор базы для работы.
+USE employees;
+
+-- Выбрать все строки и колонки из таблицы «departments» (отделы) текущей базы.
+-- В интерактивном режиме обыч но результат будет выведен на экран.
+SELECT * FROM departments;
+
+-- Тот же запрос, что и выше, но выбор только колонок «dept_no» и «dept_name».
+-- Разбиение команд на несколько строк допустимо.
+SELECT dept_no,
+ dept_name FROM departments;
+
+-- В данном случае будут выбраны все колонки, но только первые 5 строк.
+SELECT * FROM departments LIMIT 5;
+
+-- Выбор названий отделов, содержащих подстроку «en».
+SELECT dept_name FROM departments WHERE dept_name LIKE '%en%';
+
+-- Выбор всех колонок, где названия отделов начинаются на «S»,
+-- после которой идёт ровно четыре символа.
+SELECT * FROM departments WHERE dept_name LIKE 'S____';
+
+-- Выбор всех должностей из таблицы «titles», но без повторений.
+SELECT DISTINCT title FROM titles;
+
+-- В дополнение к предыдущему запросу результат будет отсортирован
+-- в алфавитном порядке (с учётом регистра).
+SELECT DISTINCT title FROM titles ORDER BY title;
+
+-- Показать число строк в таблице отделов.
+SELECT COUNT(*) FROM departments;
+
+-- Показать число строк, где название отдела содержит подстроку «en»
+SELECT COUNT(*) FROM departments WHERE dept_name LIKE '%en%';
+
+-- Объединение информации из нескольких таблиц:
+-- В таблице «titles» перечислены должности, кто их занимал по номеру сотрудника,
+-- а также с какой даты по какую. Получим эту информацию, но используем номера
+-- сотрудников как ссылку на таблицу «employees», чтобы получить имя и фамилию
+-- каждого сотрудника. Выводим только 10 строк.
+SELECT employees.first_name, employees.last_name,
+ titles.title, titles.from_date, titles.to_date
+FROM titles INNER JOIN employees ON
+ employees.emp_no = titles.emp_no LIMIT 10;
+
+-- Список всех таблиц во всех базах. Реализации обычно предоставляют
+-- собственные сокращения, чтобы показать все таблицы текущей базы.
+SELECT * FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_TYPE='BASE TABLE';
+
+-- Создать таблицу с именем tablename1 и двумя колонками в текущей базе.
+-- Для колонок имеется множество параметров, таких как тип данных.
+CREATE TABLE tablename1 (fname VARCHAR(20), lname VARCHAR(20));
+
+-- Вставляем строку данных в таблицу «tablename1». Предполагаем, что таблица
+-- настроена таким образом, чтобы принимать эти значения.
+INSERT INTO tablename1 VALUES('Richard','Mutt');
+
+-- В таблице «tablename1» изменить значение fname на «John»
+-- для каждой строки, где колонка lname равна «Mutt».
+UPDATE tablename1 SET fname='John' WHERE lname='Mutt';
+
+-- Удалить из таблицы «tablename1» строки,
+-- где значение колонки lname начинается с «M».
+DELETE FROM tablename1 WHERE lname like 'M%';
+
+-- Удалить все строки из таблицы «tablename1». В итоге получим пустую таблицу.
+DELETE FROM tablename1;
+
+-- Удалить таблицу «tablename1» полностью.
+DROP TABLE tablename1;
+```
diff --git a/ru-ru/swift-ru.html.markdown b/ru-ru/swift-ru.html.markdown
index 7ff660e1..f2b1fd36 100644
--- a/ru-ru/swift-ru.html.markdown
+++ b/ru-ru/swift-ru.html.markdown
@@ -376,14 +376,14 @@ print("Имя :\(name)") // Имя: Яков
// Протокол `Error` используется для перехвата выбрасываемых ошибок
enum MyError: Error {
- case BadValue(msg: String)
- case ReallyBadValue(msg: String)
+ case badValue(msg: String)
+ case reallyBadValue(msg: String)
}
// фунции помеченные словом `throws` должны вызываться с помощью `try`
func fakeFetch(value: Int) throws -> String {
guard 7 == value else {
- throw MyError.ReallyBadValue(msg: "Действительно плохое значение")
+ throw MyError.reallyBadValue(msg: "Действительно плохое значение")
}
return "тест"
@@ -401,7 +401,7 @@ func testTryStuff() {
do {
// обычно try оператор, позволяющий обработать ошибку в `catch` блоке
try fakeFetch(value: 1)
- } catch MyError.BadValue(let msg) {
+ } catch MyError.badValue(let msg) {
print("Ошибка: \(msg)")
} catch {
// все остальное
@@ -535,49 +535,49 @@ if let circle = myEmptyCircle {
// Они могут содержать методы подобно классам.
enum Suit {
- case Spades, Hearts, Diamonds, Clubs
+ case spades, hearts, diamonds, clubs
func getIcon() -> String {
switch self {
- case .Spades: return "♤"
- case .Hearts: return "♡"
- case .Diamonds: return "♢"
- case .Clubs: return "♧"
+ case .spades: return "♤"
+ case .hearts: return "♡"
+ case .diamonds: return "♢"
+ case .clubs: return "♧"
}
}
}
// Значения перечислений допускают сокращенный синтаксис, нет необходимости
// указывать тип перечисления, когда переменная объявляется явно
-var suitValue: Suit = .Hearts
+var suitValue: Suit = .hearts
// Значения нецелочисленных перечислений должны быть указаны явно
// или могут выводится с помощью функции `rawValue` из имени
enum BookName: String {
- case John
- case Luke = "Лука"
+ case john
+ case luke = "Лука"
}
-print("Имя: \(BookName.John.rawValue)")
+print("Имя: \(BookName.john.rawValue)")
// Перечисление (enum) со связанными значениями
enum Furniture {
// Связать с типом Int
- case Desk(height: Int)
+ case desk(height: Int)
// Связать с типами String и Int
- case Chair(String, Int)
+ case chair(String, Int)
func description() -> String {
switch self {
- case .Desk(let height):
+ case .desk(let height):
return "Письменный стол высотой \(height) см."
- case .Chair(let brand, let height):
+ case .chair(let brand, let height):
return "Стул марки \(brand) высотой \(height) см."
}
}
}
-var desk: Furniture = .Desk(height: 80)
+var desk: Furniture = .desk(height: 80)
print(desk.description()) // "Письменный стол высотой 80 см."
-var chair = Furniture.Chair("Foo", 40)
+var chair = Furniture.chair("Foo", 40)
print(chair.description()) // "Стул марки Foo высотой 40 см."
diff --git a/ru-ru/vim-ru.html.markdown b/ru-ru/vim-ru.html.markdown
index 6f62fd49..f43f99eb 100644
--- a/ru-ru/vim-ru.html.markdown
+++ b/ru-ru/vim-ru.html.markdown
@@ -9,7 +9,7 @@ filename: LearnVim-ru.txt
lang: ru-ru
---
-[Vim](www.vim.org)
+[Vim](http://www.vim.org)
(Vi IMproved) это клон полулярного текстового редактора для Unix. Он разработан
с целью повышения скорости и продуктивности и повсеместно используется в
большинство Юникс-подобных систем. В нем имеется множество клавиатурных
diff --git a/ru-ru/yaml-ru.html.markdown b/ru-ru/yaml-ru.html.markdown
new file mode 100644
index 00000000..ddaed2b6
--- /dev/null
+++ b/ru-ru/yaml-ru.html.markdown
@@ -0,0 +1,189 @@
+---
+language: yaml
+filename: learnyaml-ru.yaml
+contributors:
+- [Leigh Brenecki, 'https://github.com/adambrenecki']
+- [Suhas SG, 'https://github.com/jargnar']
+translators:
+- [Sergei Babin, 'https://github.com/serzn1']
+lang: ru-ru
+---
+
+YAML как язык сериализации данных предназначен прежде всего для использования людьми.
+
+Это строгое надмножество JSON с добавлением синтаксически значимых переносов строк и
+отступов как в Python. Тем не менее, в отличие от Python, YAML запрещает
+использование табов для отступов.
+
+```yaml
+--- # начало документа
+
+# Комментарий в YAML выглядит как-то так.
+
+######################
+# Скалярные величины #
+######################
+
+# Наш корневой объект (который продолжается до конца документа) будет соответствовать
+# типу map, который в свою очередь соответствует словарю, хешу или объекту в других языках.
+key: value
+another_key: Другое значение ключа.
+a_number_value: 100
+scientific_notation: 1e+12
+# Число 1 будет интерпретировано как число, а не как логический тип. Если необходимо чтобы
+# значение было интерпретировано как логическое, необходимо использовать true
+boolean: true
+null_value: null
+key with spaces: value
+
+# Обратите внимание что строки используются без кавычек, но могут и с кавычками.
+however: 'Строка заключенная в кавычки.'
+'Ключ заключенный в кавычки.': "Полезно если нужно использовать ':' в вашем ключе."
+single quotes: 'Содержит ''одну'' экранированную строку'
+double quotes: "Содержит несколько: \", \0, \t, \u263A, \x0d\x0a == \r\n, экранированных строк."
+
+# Многострочные строковые значения могут быть записаны как 'строковый блок' (используя |),
+# или как 'сложенный блок' (используя '>').
+literal_block: |
+ Значение всего текста в этом блоке будет присвоено ключу 'literal_block',
+ с сохранением переноса строк.
+
+ Объявление продолжается до удаления отступа и выравнивания с ведущим отступом.
+
+ Любые строки с большим отступом сохраняют остатки своего отступа -
+ эта строка будет содержать дополнительно 4 пробела.
+folded_style: >
+ Весь блок этого тектса будет значением 'folded_style', но в данном случае
+ все символы новой строки будут заменены пробелами.
+
+ Пустые строки будут преобразованы в перенос строки.
+
+ Строки с дополнительными отступами сохраняют их переносы строк -
+ этот текст появится через 2 строки.
+
+##################
+# Типы коллекций #
+##################
+
+# Вложения используют отступы. Отступ в 2 пробела предпочтителен (но не обязателен).
+a_nested_map:
+ key: value
+ another_key: Another Value
+ another_nested_map:
+ hello: hello
+
+# В словарях (maps) используются не только строковые значения ключей.
+0.25: a float key
+
+# Ключи также могут быть сложными, например многострочными.
+# Мы используем ? с последующим пробелом чтобы обозначить начало сложного ключа.
+? |
+ Этот ключ
+ который содержит несколько строк
+: и это его значение
+
+# YAML также разрешает соответствия между последовательностями со сложными ключами
+# Некоторые парсеры могут выдать предупреждения или ошибку
+# Пример
+? - Manchester United
+ - Real Madrid
+: [2001-01-01, 2002-02-02]
+
+# Последовательности (эквивалент списка или массива) выглядят как-то так
+# (обратите внимание что знак '-' считается отступом):
+a_sequence:
+ - Item 1
+ - Item 2
+ - 0.5 # последовательности могут содержать различные типы.
+ - Item 4
+ - key: value
+ another_key: another_value
+ -
+ - Это последовательность
+ - внутри другой последовательности
+ - - - Объявления вложенных последовательностей
+ - могут быть сжаты
+
+# Поскольку YAML это надмножество JSON, вы можете использовать JSON-подобный
+# синтаксис для словарей и последовательностей:
+json_map: {"key": "value"}
+json_seq: [3, 2, 1, "takeoff"]
+в данном случае кавычки не обязательны: {key: [3, 2, 1, takeoff]}
+
+##########################
+# Дополнительные функции #
+##########################
+
+# В YAML есть удобная система так называемых 'якорей' (anchors), которые позволяют легко
+# дублировать содержимое внутри документа. Оба ключа в примере будут иметь одинаковые значения:
+anchored_content: &anchor_name Эта строка будет являться значением обоих ключей.
+other_anchor: *anchor_name
+
+# Якоря могут использоваться для дублирования/наследования свойств
+base: &base
+ name: Каждый будет иметь одинаковое имя
+
+# Регулярное выражение << называется ключом объединения независимо от типа языка.
+# Он используется чтобы показать что все ключи одного или более словарей должны быть
+# добавлены в текущий словарь.
+
+foo: &foo
+ <<: *base
+ age: 10
+
+bar: &bar
+ <<: *base
+ age: 20
+
+# foo и bar могли бы иметь имена: Каждый из них имеет аналогичное имя
+
+# В YAML есть теги (tags), которые используются для явного объявления типов.
+explicit_string: !!str 0.5
+# В некоторых парсерах реализованы теги для конкретного языка, пример для Python
+# пример сложного числового типа.
+python_complex_number: !!python/complex 1+2j
+
+# Мы можем использовать сложные ключи с включенными в них тегами из определенного языка
+? !!python/tuple [5, 7]
+: Fifty Seven
+# Могло бы быть {(5, 7): 'Fifty Seven'} в Python
+
+#######################
+# Дополнительные типы #
+#######################
+
+# Строки и числа не единственные величины которые может понять YAML.
+# YAML также поддерживает даты и время в формате ISO.
+datetime: 2001-12-15T02:59:43.1Z
+datetime_with_spaces: 2001-12-14 21:59:43.10 -5
+date: 2002-12-14
+
+# Тег !!binary показывает что эта строка является base64-закодированным
+# представлением двоичного объекта.
+gif_file: !!binary |
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=
+
+# YAML может использовать объекты типа ассоциативных массивов (set), как представлено ниже:
+set:
+ ? item1
+ ? item2
+ ? item3
+or: {item1, item2, item3}
+
+# Сеты (set) являются простыми эквивалентами словарей со значениями
+# типа null; запись выше эквивалентна следующей:
+set2:
+ item1: null
+ item2: null
+ item3: null
+
+... # конец документа
+```
+
+### Больше информации
+
++ [YAML оффициальный вебсайт](http://yaml.org/)
++ [YAML онлайн валидатор](http://www.yamllint.com/)