Эликсир: соответствие шаблонов работает по-разному для кортежей и карт

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

{a} = {1, 2}

Я получаю ошибку совпадения. Но если я сделаю то же самое для двух карт:

%{x: a} = %{x: 1, y: 2}

Он отлично работает, а a связывается с 1. Я вижу, почему совпадение двух кортежей дало ошибку, но почему сопоставление карт не приводило к ошибке?

Ответ 1

В первом примере вы пытаетесь сопоставить один кортеж элемента с двухэлементным кортежем. Во втором примере вы сопоставляетесь по ключу: x в левой и правой картах.

EDIT: я должен уточнить правила вокруг структур данных и сопоставления образцов в Elixir.

При сопоставлении с кортежами вам необходимо предоставить шаблон, который соответствует всей структуре кортежа. Вы можете использовать _, который является шаблоном "catch-all", но вам все равно нужно предоставить его для всех элементов кортежа. При сопоставлении списков вы должны сопоставлять либо все элементы при использовании синтаксиса [a, b, c] = [1, 2, 3], либо на голове и хвосте, используя синтаксис [h|t] = [1, 2, 3]. Однако при сопоставлении карт вы можете сопоставлять один или несколько ключей на карте, что дает синтаксис %{a: b} = %{a: :foo, b: :bar}.

Семантика немного отличается между структурами данных, но они довольно распространены. Правило кортежа существует, потому что два кортежа не могут быть одинаковыми, если они не имеют одинакового количества элементов, список имеет одинаковые ограничения, но из-за семантики списков доступ к элементу головы списка является наиболее распространенной операцией при работе с их, следовательно, синтаксис [h|t]. Карты, однако, могут соответствовать на основе определенных ключей, поэтому количество элементов не имеет значения, если обе стороны матча содержат один и тот же ключ и необязательный шаблон для значения, то это успешное совпадение.

Ответ 2

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

A map может фактически соответствовать шаблону только подмножеством значения. Ключ в шаблоне должен существовать в матче, но обе структуры не должны отражать друг друга таким же образом, как и для list или tuple. Например:

iex(1)> [a, b] = [1, 2, 3]
** (MatchError) no match of right hand side value: [1, 2, 3]

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

iex(1)> %{:a => one} = %{:a => 1, :b => 2, :c =>3}
%{a: 1, b: 2, c: 3}
iex(2)> one
1
iex(3)> %{:a => one, :c => three} = %{:a => 1, :b => 2, :c =>3}
%{a: 1, b: 2, c: 3}
iex(4)> three
3
iex(5)> one
1
iex(6)> %{} = %{:a => 1, :b => 2, :c =>3}
%{a: 1, b: 2, c: 3}
iex(7)> %{:d => four} = %{:a => 1, :b => 2, :c =>3}
** (MatchError) no match of right hand side value: %{a: 1, b: 2, c: 3}

iex(8)> %{:a => one, :d => four} = %{:a => 1, :b => 2, :c =>3}
** (MatchError) no match of right hand side value: %{a: 1, b: 2, c: 3}

Мы можем видеть, что ни list, ни tuple не совпадают, если структура данных шаблона отличается от структуры данных совпадения, а именно размера. В то время как это не относится к карте. Поскольку ключ присутствует как в шаблоне, так и в матче, то совпадение выполняется успешно, независимо от разных размеров шаблона и совпадения. Пустой map также будет соответствовать.

Однако совпадение не будет успешным, если ключ в шаблоне не совпадает. Это также имеет место, даже если есть соответствующие ключи. Поэтому любой символ, используемый в шаблоне, должен присутствовать в матче.

Вы увидите, что этот вид соответствия широко используется в Phoenix Framework для получения только необходимых параметров из запроса.

Источник: - Заметки об эликсире: сопоставления с образцами