Spec-Zone.ru › Elixir 1.17

Источник case, cond и if

В этой главе мы изучим case, cond, и if конструкции управления потоком.

case

case позволяет нам сравнивать значение с множеством шаблонов, пока мы не найдем соответствующий:

iex> case {1, 2, 3} do
...>   {4, 5, 6} ->
...>     "This clause won't match"
...>   {1, x, 3} ->
...>     "This clause will match and bind x to 2 in this clause"
...>   _ ->
...>     "This clause would match any value"
...> end
"This clause will match and bind x to 2 in this clause"

Если вы хотите сопоставить шаблон с существующей переменной, вам необходимо использовать оператор ^:

iex> x = 1
1
iex> case 10 do
...>   ^x -> "Won't match"
...>   _ -> "Will match"
...> end
"Will match"

В правилах также можно указать дополнительные условия с помощью защит:

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Would match, if guard condition were not satisfied"
...> end
"Will match"

Первое правило выше будет соответствовать только тогда, когда x положительно.

Обратите внимание, что ошибки в защитах не передаются, а просто приводят к провалу защиты:

iex> hd(1)
** (ArgumentError) argument error
iex> case 1 do
...>   x when hd(x) -> "Won't match"
...>   x -> "Got #{x}"
...> end
"Got 1"

Если ни одному из правил не соответствует, генерируется ошибка:

iex> case :ok do
...>   :error -> "Won't match"
...> end
** (CaseClauseError) no case clause matching: :ok

Документация по модулю Kernel содержит список всех доступных защит в боковой панели. Вы также можете обратиться к полному справочнику Шаблоны и Защиты для получения подробной документации.

if/unless

case опирается на сопоставление шаблонов и защит для деструктуризации и сопоставления с определёнными условиями. Однако шаблоны и защиты ограничены только определёнными выражениями, которые оптимизируются компилятором. В многих ситуациях вам нужно написать условия, выходящие за рамки того, что можно выразить с case. Для этого if/2 (и unless/2) являются полезными альтернативами:

iex> if true do
...>   "This works!"
...> end
"This works!"
iex> unless true do
...>   "This will never be seen"
...> end
nil

Если условие, заданное для if/2, возвращает false или nil, тело, заданное между do-end, не выполняется, а вместо этого возвращается nil. Обратное происходит с unless/2.

Они также поддерживают else блоки (хотя использование else с unless обычно не рекомендуется):

iex> if nil do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

Это также хорошая возможность поговорить о области видимости переменных в Elixir. Если любая переменная объявлена или изменена внутри if, case, и аналогичных конструкций, объявление и изменение будут видимы только внутри конструкции. Например:

iex> x = 1
1
iex> if true do
...>   x = x + 1
...> end
2
iex> x
1

В таких случаях, если вы хотите изменить значение, вы должны вернуть значение из if:

iex> x = 1
1
iex> x = if true do
...>   x + 1
...> else
...>   x
...> end
2

if и unless — макросы

Интересно отметить, что if/2 и unless/2 реализованы как макросы в языке: они не являются специальными конструкциями языка, как в многих других языках. Вы можете проверить документацию и их исходный код для получения дополнительной информации.

Если вы обнаружите себя вложенными несколькими блоками if/2, возможно, стоит рассмотреть использование cond/1 вместо этого. Давайте посмотрим.

cond

Если вам нужно проверить несколько условий и найти первое, которое не оценивается как nil или false, cond/1 является полезной конструкцией:

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...> end
"But this will"

Это эквивалентно правилам else if во многих императивных языках — хотя используется реже в Elixir.

Если все условия возвращают nil или false, возникает ошибка (CondClauseError). По этой причине может потребоваться добавить конечное условие, равное true, которое всегда будет соответствовать:

iex> cond do
...>   2 + 2 == 5 ->
...>     "This is never true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   true ->
...>     "This is always true (equivalent to else)"
...> end
"This is always true (equivalent to else)"

Подобно if/2 и unless/2, cond считает любое значение, кроме nil и false, истинным:

iex> cond do
...>   hd([1, 2, 3]) ->
...>     "1 is considered as true"
...> end
"1 is considered as true"

Подведение итогов

Мы завершили введение в наиболее фундаментальные конструкции управления потоком в Elixir. В общем, разработчики Elixir предпочитают сопоставление шаблонов и защит, используя case и определения функций (которые мы изучим в будущих главах), поскольку они лаконичны и точны. Когда ваша логика не может быть описана с помощью шаблонов и защит, вы можете рассмотреть if/2, возвращаясь к cond/1, когда нужно проверить несколько условий.

← Предыдущая страница Сопоставление шаблонов
Следующая страница → Анонимные функции

Скачать версию ePub

Создано с помощью ExDoc (v0.34.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/case-cond-and-if.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API