Spec-Zone.ru › Elixir 1.16

Source Сопоставление с образцом

В этой главе мы узнаем, почему оператор = в Elixir называется оператором сопоставления и как использовать его для сопоставления с образцом внутри структур данных. Мы узнаем об операторе фиксации ^ используемом для доступа к ранее связанным значениям.

Оператор сопоставления

Мы несколько раз использовали оператор = для присваивания переменных в Elixir:

iex> x = 1
1
iex> x
1

В Elixir, оператор = фактически называется оператором сопоставления. Давайте посмотрим почему:

iex> x = 1
1
iex> 1 = x
1
iex> 2 = x
** (MatchError) no match of right hand side value: 1

Обратите внимание, что 1 = x является допустимым выражением, и оно совпало, потому что обе левая и правая части равны 1. Когда стороны не совпадают, генерируется ошибка MatchError.

Переменной можно присвоить значение только в левой части оператора =:

iex> 1 = unknown
** (CompileError) iex:1: undefined variable "unknown"

Сопоставление с образцом

Оператор сопоставления используется не только для сопоставления со простыми значениями, но и для деструктуризации более сложных типов данных. Например, мы можем сопоставить с образцом кортежи:

iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"

Ошибка сопоставления с образцом произойдёт, если стороны не могут быть сопоставлены, например, если кортежи имеют разный размер:

iex> {a, b, c} = {:hello, "world"}
** (MatchError) no match of right hand side value: {:hello, "world"}

А также при сравнении разных типов, например, если сопоставлять кортеж в левой части со списком в правой:

iex> {a, b, c} = [:hello, "world", 42]
** (MatchError) no match of right hand side value: [:hello, "world", 42]

Более интересно, мы можем сопоставлять со специфическими значениями. Пример ниже утверждает, что левая часть будет соответствовать правой части только тогда, когда правая часть является кортежем, начинающимся с атома :ok:

iex> {:ok, result} = {:ok, 13}
{:ok, 13}
iex> result
13

iex> {:ok, result} = {:error, :oops}
** (MatchError) no match of right hand side value: {:error, :oops}

Мы можем сопоставлять с образцом списки:

iex> [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex> a
1

Список также поддерживает сопоставление с образцом своего собственного заголовка и хвоста:

iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]

Аналогично функциям hd/1 и tl/1, мы не можем сопоставить пустой список с образцом заголовка и хвоста:

iex> [head | tail] = []
** (MatchError) no match of right hand side value: []

Формат [head | tail] используется не только для сопоставления с образцом, но и для добавления элементов в начало списка:

iex> list = [1, 2, 3]
[1, 2, 3]
iex> [0 | list]
[0, 1, 2, 3]

Сопоставление с образцом позволяет разработчикам легко деструктурировать типы данных, такие как кортежи и списки. Как мы увидим в следующих главах, это один из фундаментов рекурсии в Elixir и применяется и к другим типам, таким как карты и бинарные данные.

Оператор фиксации

Переменные в Elixir могут быть переприсвоены:

iex> x = 1
1
iex> x = 2
2

Однако есть случаи, когда мы не хотим, чтобы переменные переприсваивались.

Используйте оператор фиксации ^ когда вы хотите сопоставить с образцом существующее значение переменной, а не переприсваивать переменную.

iex> x = 1
1
iex> ^x = 2
** (MatchError) no match of right hand side value: 2

Поскольку мы зафиксировали x, когда оно было присвоено значению 1, это эквивалентно следующему:

iex> 1 = 2
** (MatchError) no match of right hand side value: 2

Обратите внимание, что мы даже видим то же самое сообщение об ошибке.

Мы можем использовать оператор фиксации внутри других сопоставлений с образцом, таких как кортежи или списки:

iex> x = 1
1
iex> [^x, 2, 3] = [1, 2, 3]
[1, 2, 3]
iex> {y, ^x} = {2, 1}
{2, 1}
iex> y
2
iex> {y, ^x} = {2, 2}
** (MatchError) no match of right hand side value: {2, 2}

Поскольку x было присвоено значение 1 при фиксации, этот последний пример можно было бы записать как:

iex> {y, 1} = {2, 2}
** (MatchError) no match of right hand side value: {2, 2}

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

iex> {x, x} = {1, 1}
{1, 1}
iex> {x, x} = {1, 2}
** (MatchError) no match of right hand side value: {1, 2}

В некоторых случаях вам не нужно конкретное значение в шаблоне. Принято связывать такие значения с символом нижнего подчеркивания, _. Например, если нам важен только заголовок списка, мы можем присвоить хвост символу нижнего подчеркивания:

iex> [head | _] = [1, 2, 3]
[1, 2, 3]
iex> head
1

Переменная _ является специальной, так как её нельзя прочитать. Попытка её прочитать вызывает ошибку компиляции:

iex> _
** (CompileError) iex:1: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions

Хотя сопоставление с образцом позволяет строить мощные конструкции, его использование ограничено. Например, вы не можете делать вызовы функций в левой части сопоставления. Следующий пример недействителен:

iex> length([1, [2], 3]) = 3
** (CompileError) iex:1: cannot invoke remote function :erlang.length/1 inside match

Это завершает наше введение в сопоставление с образцом. Как мы увидим в следующей главе, сопоставление с образцом очень часто используется во многих языковых конструкциях, и его можно дополнительно расширить с помощью стражей.

← Предыдущая страница Списки и кортежи
Следующая страница → case, cond и if

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

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

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/pattern-matching.html

Spec-Zone.ru

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