summaryrefslogtreecommitdiffhomepage
path: root/ru-ru/elixir-ru.html.markdown
blob: 641501423869061fb96c3986c7fe80836cec8092 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
---
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."

```