Есть некоторые нюансы сопоставления с образцом при работе со словарями. В шаблоне не нужно перечислять все ключи, какие есть в словаре. Мы указываем только те ключи, которые нам нужны:
my_map = %{a: 1, b: 2, c: 3}
%{a: value} = my_map
IO.puts(value) # => 1
Если ключи не являются атомами, то синтаксис отличается:
my_map = %{"a" => 1, "b" => 2, "c" => 3}
%{"a" => value1} = my_map
IO.puts(value1) # => 1
%{"b" => value2, "c" => value3} = my_map
IO.puts(value2) # => 2
IO.puts(value3) # => 3
Шаблон %{}
совпадает с любым словарём. Это контринтуитивно, можно было бы ожидать, что этот шаблон совпадает только с пустым словарём. Этим шаблоном нельзя ничего извлечь, но можно проверить, что значение является словарём, а не чем-то иным.
my_map = %{"a" => 1, "b" => 2, "c" => 3}
%{} = my_map
my_map = 42
%{} = my_map # ** (MatchError) no match of right hand side value: 42
Переменные можно использовать для извлечения значений, но не для извлечения ключей:
%{"c" => my_var} = my_map
IO.puts(my_var) # => 3
%{my_var => 1} = my_map # ** (CompileError) iex:17: cannot use variable my_var as map key inside a pattern.
Переменная в шаблоне может выполнять две роли. Либо мы хотим, чтобы эта переменная получила новое значение, и тогда не важно, использовалась ли эта переменная раньше, было ли у нее какое-то значение. Либо мы хотим использовать значение, которое переменная уже имеет, как часть шаблона. Во втором случае понадобится pin operator.
animal = :cat
{^animal, "Tihon"} = {:cat, "Tihon"}
{^animal, "Tihon"} = {:dog, "Tihon"} # ** (MatchError) no match of right hand side value: {:dog, "Tihon"}
pin operator извлекает текущее значение переменной и подставляет его в шаблон. И дальше это значение в шаблоне работает как литерал.
pin operator можно использовать и для ключа, и для значения:
value1 = 1
%{"a" => ^value1} = my_map
keyb = "b"
%{^keyb => _} = my_map
Реализовать функцию get_values(data)
, которая принимает словарь, извлекает из него два значения по ключам :a
и :b
, и возвращает их в виде кортежа {a_value, b_value}
.
Реализовать функцию get_value_by_key(data, key)
, которая принимает словарь и ключ, извлекает значение по указанному ключу и возвращает его.
Обе функции генерируют исключение MatchError
если в словаре нет нужных ключей.
Solution.get_values(%{a: 1, b: 2})
# => {1, 2}
Solution.get_values(%{a: :ok, b: 42, c: true})
# => {:ok, 42}
Solution.get_values(%{})
# => MatchError
Solution.get_value_by_key(%{answer: 42}, :answer)
# => 42
Solution.get_value_by_key(%{question: "6 * 7"}, :question)
# => "6 * 7"
Solution.get_value_by_key(%{a: 1}, :b)
# => MatchError
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1defmodule Test do
2 use ExUnit.Case
3 import Solution
4
5 test "get_values test" do
6 assert {1, 2} = get_values(%{a: 1, b: 2})
7 assert {:ok, 42} = get_values(%{a: :ok, b: 42, c: true})
8 end
9
10 test "get_values invalid input test" do
11 assert_raise MatchError, fn ->
12 get_values(%{})
13 end
14 end
15
16 test "get_value_by_key test" do
17 assert 42 = get_value_by_key(%{answer: 42}, :answer)
18 assert "6 * 7" = get_value_by_key(%{question: "6 * 7"}, :question)
19 end
20
21 test "get_value_by_key invalid input test" do
22 assert_raise MatchError, fn ->
23 get_value_by_key(%{a: 1}, :b)
24 end
25 end
26end
27
Решение учителя откроется через: