Maps - это key-value структуры данных.
Maps - это key-value структуры данных.
Неизменяемость и создание нового `Map` в Elixir
В Elixir структуры данных, такие как Map, являются неизменяемыми. Это означает, что вы не можете изменить их "на месте". Вместо этого, когда вы пытаетесь изменить Map, вы создаете новую структуру данных, а старая остаётся нетронутой. Это важное свойство, которое помогает избежать побочных эффектов в функциональном программировании.
Разбор вашего примера
Ваш пример:
☯
Terminal:
⌕
≡
✕
map = %{a: 1, b: 2}
new_map = %{map | a: 3}- Исходный
map: Вы имеетеmapс двумя ключами:aи:b, где:aимеет значение1, а:b—2. - Создание нового
Map: Когда вы делаете%{map | a: 3}, вы создаете новыйMap, в котором ключ:aобновляется на3. НовыйMapбудет выглядеть так:%{a: 3, b: 2}.
Где старая версия `Map`?
- Старая версия (или исходный
map), где:aравно1, всё еще существует в памяти и доступна. Вы можете ссылаться на неё с помощью переменнойmap, которая была определена раньше: ``elixir IO.inspect(map) # Выведет %{a: 1, b: 2} IO.inspect(new_map) # Выведет %{a: 3, b: 2}``
Преимущества неизменяемости
- Безопасность: Поскольку данные неизменяемы, вы исключаете возможность случайного изменения значений в коде.
- Простота отладки: Легче отслеживать состояние данных в программе, так как вы всегда знаете, что изменения создают новые копии.
- Поддержка параллелизма: Неизменяемые структуры обеспечивают безопасный доступ из разных потоков или процессов, поскольку данные не будут изменяться "на лету".
Заключение
Неизменяемость в Elixir важна для обеспечения предсказуемости и безопасности кода. Когда вы создаете новый Map, весь предыдущий контекст остается доступным и неизменным, что делает функциональное программирование удобным для управления состоянием.
ключи строки
m = %{"a" => 42, "b" => 100}
кдючи атомы
m2 = %{:a => 42, :b =>100}
iex(1)> m = %{"a" => 42, "b" => 100}
%{"a" => 42, "b" => 100}
iex(2)> m["b"]
100
iex(3)> m["c"]
nil
iex(4)> m2 = %{:a => 42, :b =>100}
%{a: 42, b: 100}
iex(12)> %{:a => 42, :b =>100} = %{a: 42, b: 100}
%{a: 42, b: 100}
iex(5)> m[:a]
nil
iex(6)> m2[:a]
42
iex(7)> m2.a
42
iex(8)> m2.c
** (KeyError) key :c not found in: %{a: 42, b: 100}
iex(8)> Map.get(m,"a")
42
iex(9)> Map.get(m2,"a")
nil
iex(10)> Map.get(m2,"a",:default)
:default
iex(11)> Map.fetch(m2, :b)
{:ok, 100}
iex(13)> Map.fetch(m2, :c)
:error
с восклицательным знаком
iex(14)> Map.fetch!(m2, :c)
** (KeyError) key :c not found in: %{a: 42, b: 100}
(stdlib 4.2) :maps.get(:c, %{a: 42, b: 100})
iex(14)> Map.fetch!(m2, :b)
100
имутабельность данных не меняет мапу а создаёт новый мам
iex(15)> Map.put(m, :c, 500)
%{:c => 500, "a" => 42, "b" => 100}
iex(16)> m
%{"a" => 42, "b" => 100}
iex(17)> m3=Map.put(m, :c, 500)
%{:c => 500, "a" => 42, "b" => 100}
iex(18)> m
%{"a" => 42, "b" => 100}
iex(19)> m3
%{:c => 500, "a" => 42, "b" => 100}
существующем ключе меняется значение
iex(20)> m3=Map.put(m3, :c, 5050)
%{:c => 5050, "a" => 42, "b" => 100}
iex(21)> m3
%{:c => 5050, "a" => 42, "b" => 100}
изменить значение существующих ключей:
%{"a" => 42, "b" => 100}
| iex(2)> %{m | a: 43, b: 108} |
** (KeyError) key :a not found in: %{"a" => 42, "b" => 100}
(stdlib 4.2) :maps.update(:a, 43, %{"a" => 42, "b" => 100})
(stdlib 4.2) erl_eval.erl:309: anonymous fn/2 in :erl_eval.expr/6
(stdlib 4.2) lists.erl:1350: :lists.foldl/3
| iex(2)> %{m | "a" 43, "b" 108} |
** (SyntaxError) iex:2:11: syntax error before: "43"
| 2 | %{m | "a" 43, "b" 108} |
| ^ |
| iex(2)> %{m | "a" => 43, "b" => 108} |
%{"a" => 43, "b" => 108}
iex(3)> m
%{"a" => 42, "b" => 100}
Отлично ?
Ниже — полная таблица всех функций для работы с Map в Elixir, с короткими описаниями и примерами, в том же формате, что и предыдущие шпаргалки (для String и List).
Актуально для Elixir 1.17 / OTP 27.
? Модуль `Map`
> Map — основной модуль для работы с ассоциативными коллекциями (%{ключ => значение}),
> где ключи могут быть любыми сравнимыми типами (обычно — атомы, числа или строки).
? Создание и базовые операции
| Функция | Назначение | Пример |
%{} | Литерал map | %{a: 1, b: 2} |
Map.new/0 | Пустая карта | Map.new() #=> %{} |
Map.new/1 | Из перечисления | Map.new([{:a,1},{:b,2}]) #=> %{a: 1, b: 2} |
Map.new/2 | Преобразование с функцией | Map.new([1,2,3], fn x -> {x, x*x} end) #=> %{1=>1,2=>4,3=>9} |
%{map | key => val} | Обновление значения (ключ должен существовать) | m=%{a:1}; %{m | a:2} #=> %{a:2} |
Map.put/3 | Добавить/заменить пару | Map.put(%{a:1}, :b, 2) #=> %{a:1,b:2} |
Map.put_new/3 | Добавить только если ключа нет | Map.put_new(%{a:1}, :a, 9) #=> %{a:1} |
Map.put_new_lazy/3 | Вычислить значение лениво | Map.put_new_lazy(%{}, :x, fn -> 42 end) |
Map.update/4 | Обновить значение с функцией | Map.update(%{a:1}, :a, 0, &(&1+1)) #=> %{a:2} |
Map.update!/3 | То же, но без значения по умолчанию | Map.update!(%{a:1}, :a, &(&1+1)) #=> %{a:2} |
Map.replace!/3 | Заменить, если ключ существует | Map.replace!(%{a:1}, :a, 9) #=> %{a:9} |
Map.replace/3 | Заменить, не создавая новый ключ | Map.replace(%{a:1}, :b, 2) #=> %{a:1} |
? Чтение и доступ
| Функция | Назначение | Пример |
Map.get/2 | Получить значение | Map.get(%{a:1}, :a) #=> 1 |
Map.get/3 | С дефолтным значением | Map.get(%{}, :x, 0) #=> 0 |
Map.fetch/2 | Возвращает {:ok, val} или :error | Map.fetch(%{a:1}, :a) #=> {:ok,1} |
Map.fetch!/2 | Как get, но бросает ошибку | Map.fetch!(%{a:1}, :b) #=> KeyError |
Map.get_lazy/3 | Значение по умолчанию вычисляется функцией | Map.get_lazy(%{}, :x, fn -> 99 end) |
Map.pop/2 | Извлечь и удалить ключ | Map.pop(%{a:1,b:2}, :a) #=> {1, %{b:2}} |
Map.pop/3 | С дефолтным значением | Map.pop(%{}, :x, 0) #=> {0, %{}} |
Map.pop_lazy/3 | Дефолт вычисляется функцией | Map.pop_lazy(%{}, :x, fn -> 5 end) |
Map.get_and_update/3 | Получить и изменить через функцию | Map.get_and_update(%{a:1}, :a, fn val -> {val, val+1} end) |
Map.get_and_update!/3 | Как выше, но без дефолта | Map.get_and_update!(%{a:1}, :a, fn v -> {v, v*2} end) |
? Удаление ключей
| Функция | Назначение | Пример |
Map.delete/2 | Удалить по ключу | Map.delete(%{a:1,b:2}, :a) #=> %{b:2} |
Map.drop/2 | Удалить несколько ключей | Map.drop(%{a:1,b:2,c:3}, [:a,:b]) #=> %{c:3} |
Map.take/2 | Оставить только указанные ключи | Map.take(%{a:1,b:2}, [:a]) #=> %{a:1} |
Map.pop/2 | Извлечь и удалить | Map.pop(%{x:1}, :x) #=> {1, %{}} |
? Информация и проверка
| Функция | Назначение | Пример |
Map.has_key?/2 | Проверяет наличие ключа | Map.has_key?(%{a:1}, :a) #=> true |
Map.equal?/2 | Проверяет равенство двух карт | Map.equal?(%{a:1}, %{a:1}) #=> true |
map_size/1 (Kernel) | Кол-во пар | map_size(%{a:1,b:2}) #=> 2 |
? Извлечение ключей и значений
| Функция | Назначение | Пример |
Map.keys/1 | Список ключей | Map.keys(%{a: 1,b: 2}) #=> [:a,:b] |
Map.values/1 | Список значений | Map.values(%{a: 1,b: 2}) #=> [1,2] |
Map.to_list/1 | Преобразовать в keyword-пары | Map.to_list(%{a: 1,b: 2}) #=> [a:1,b:2] |
Enum.into/2 | Преобразовать коллекцию в map | Enum.into([{:a , 1}], %{}) #=> %{a:1} |
? Объединение и слияние
| Функция | Назначение | Пример |
Map.merge/2 | Объединяет два map | Map.merge(%{a:1}, %{b:2}) #=> %{a:1,b:2} |
Map.merge/3 | С пользовательской функцией | Map.merge(%{a:1}, %{a:10}, fn _k,v1,v2 -> v1+v2 end) #=> %{a:11} |
Enum.into/2 | Слияние коллекции в map | Enum.into([{:x,9}], %{a:1}) #=> %{a:1,x:9} |
? Преобразование
| Функция | Назначение | Пример |
Map.from_struct/1 | Структура → map | Map.from_struct(%URI{path: "/foo"}) |
Map.to_list/1 | Map → список пар | Map.to_list(%{a:1,b:2}) #=> [a:1,b:2] |
Map.new/1 | Список пар → map | Map.new([{:a,1},{:b,2}]) |
? Структуры (`struct`)
| Функция | Назначение | Пример |
Map.from_struct/1 | Преобразует структуру в map | Map.from_struct(%URI{path: "/foo"}) |
Map.merge/2 | Объединяет два map или структуры | Map.merge(%URI{}, %{path: "/"}) |
Kernel.struct/2 | Создаёт структуру из map | struct(User, %{name: "Tom"}) |
Kernel.struct!/2 | То же, но требует все ключи | struct!(User, %{name: "Tom", age: 20}) |
? Сопоставление с образцом
| Конструкция | Назначение | Пример |
%{key: val} = map | Деструктуризация | %{a: x} = %{a: 10, b: 20} #=> x=10 |
%{key => value} | Динамические ключи | key=:a; %{^key => v} = %{a: 1} #=> v=1 |
Map.fetch!/2 | Проверка при pattern match | Map.fetch!(map, :x) |
? Из `Enum` и `Kernel` (часто применяются к map)
| Функция | Назначение | Пример |
Enum.map/2 | Преобразовать пары | Enum.map(%{a:1,b:2}, fn {k,v} -> {k,v*2} end) |
Enum.each/2 | Итерация | Enum.each(%{a:1}, fn {k,v} -> IO.puts("#{k}=#{v}") end) |
Enum.filter/2 | Фильтрация по условию | Enum.filter(%{a:1,b:2}, fn {_,v} -> v>1 end) |
Enum.into/2 | Преобразовать в map | Enum.into([{:x,1}], %{}) |
Map.merge/2 | Объединить два map | Map.merge(%{a:1}, %{b:2}) |
? Пример частых комбинаций
| Цель | Пример |
| Получить или задать значение по ключу | m = %{x: 1}; m[:x] #=> 1; %{m | x: 2} |
| Объединить с дефолтами | Map.merge(%{a:1}, %{a:99,b:2}, fn _,v1,_ -> v1 end) |
| Удалить несколько ключей | Map.drop(m, [:a,:b]) |
| Оставить только нужные | Map.take(m, [:id,:name]) |
| Проверить ключ | Map.has_key?(m, :id) |
| Преобразовать значения | Enum.map(m, fn {k,v} -> {k, v*2} end) | > Enum.into(%{}) |
⚙️ Полезные из `Kernel` (работают с map напрямую)
| Функция/оператор | Назначение | Пример |
m[:key] | Получение значения (или nil) | %{a:1}[:a] #=> 1 |
%{m | key: value} | Обновить существующий ключ | %{a:1,b:2} | > Map.put(:c,3) |
map_size/1 | Количество пар | map_size(%{a:1,b:2}) #=> 2 |
is_map/1 | Проверка типа | is_map(%{}) #=> true |
Примеры использования функции `Map.put` в Elixir
Функция Map.put позволяет добавлять или обновлять значения в структуре данных типа Map. Она принимает три аргумента:
- Исходный
Map. - Ключ, под которым нужно сохранить значение.
- Значение, которое нужно сохранить.
После выполнения Map.put возвращается новая версия Map, содержащая обновленные данные.
Примеры использования
1. Добавление нового элемента
☯
Terminal:
⌕
≡
✕
map = %{a: 1, b: 2}
updated_map = Map.put(map, :c, 3)
# Результат
# updated_map будет %{a: 1, b: 2, c: 3}2. Обновление существующего элемента
☯
Terminal:
⌕
≡
✕
map = %{a: 1, b: 2}
updated_map = Map.put(map, :b, 3)
# Результат
# updated_map будет %{a: 1, b: 3}3. Использование с различными типами ключей и значений
☯
Terminal:
⌕
≡
✕
map = %{"name" => "John", age: 30}
updated_map = Map.put(map, :email, "john@example.com")
# Результат
# updated_map будет %{"name" => "John", age: 30, email: "john@example.com"}4. Вложенные Maps
☯
Terminal:
⌕
≡
✕
map = %{user: %{name: "Alice", age: 25}}
updated_map = Map.put(map, :user, Map.put(map.user, :age, 26))
# Результат
# updated_map будет %{user: %{name: "Alice", age: 26}}5. Использование в функциях
Вы можете использовать Map.put внутри других функций, чтобы обновлять значения по мере необходимости.
☯
Terminal:
⌕
≡
✕
defmodule User do
def update_email(user, new_email) do
Map.put(user, :email, new_email)
end
end
user = %{name: "Alice", email: "old_email@example.com"}
updated_user = User.update_email(user, "new_email@example.com")
# Результат
# updated_user будет %{name: "Alice", email: "new_email@example.com"}-
Создано 18.11.2025 22:13:26
-
Roman Sakhno

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.