diff options
author | Dmitrii Kuznetsov <torgeek@gmail.com> | 2021-02-22 18:42:33 +0300 |
---|---|---|
committer | Dmitrii Kuznetsov <torgeek@gmail.com> | 2021-02-22 18:42:33 +0300 |
commit | e09fefaa3e78c645c720c86391e3f96d257be8a9 (patch) | |
tree | 0ff8b235e3e707125e2b11d5268ad085832355cb /ru-ru | |
parent | f4c740839d78f797e9cbcfa1eb0483ac0ea45501 (diff) | |
parent | bc8bd2646f068cfb402850f7c0f9b1dbfe81e5a0 (diff) |
Merge branch 'master' of https://github.com/torgeek/learnxinyminutes-docs
Diffstat (limited to 'ru-ru')
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 + &= "Да & да" + +/ выведет 'Да & да' + +/ + Чтобы выполнять 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/) |