--- 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-строки являются бинарными # данными. <> #=> "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." ```