Elixir映射 #
一、映射基础 #
1.1 映射定义 #
映射是键值对的集合,键可以是任意类型:
elixir
iex(1)> %{:name => "Alice", :age => 30}
%{age: 30, name: "Alice"}
iex(2)> %{"name" => "Bob", "age" => 25}
%{"age" => 25, "name" => "Bob"}
iex(3)> %{1 => "one", 2 => "two"}
%{1 => "one", 2 => "two"}
1.2 原子键简写 #
当键是原子时,可以使用简写语法:
elixir
iex(1)> %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> %{:name => "Alice", :age => 30}
%{age: 30, name: "Alice"}
1.3 空映射 #
elixir
iex(1)> %{}
%{}
1.4 映射大小 #
elixir
iex(1)> map_size(%{a: 1, b: 2, c: 3})
3
二、访问与更新 #
2.1 访问值 #
点号语法(仅原子键) #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> user.name
"Alice"
iex(3)> user.age
30
方括号语法 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> user[:name]
"Alice"
iex(3)> user[:unknown]
nil
Map.get函数 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> Map.get(user, :name)
"Alice"
iex(3)> Map.get(user, :unknown)
nil
iex(4)> Map.get(user, :unknown, "default")
"default"
2.2 更新值 #
更新语法 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> %{user | age: 31}
%{age: 31, name: "Alice"}
iex(3)> %{user | name: "Bob", age: 25}
%{age: 25, name: "Bob"}
注意:只能更新已存在的键。
Map.put函数 #
elixir
iex(1)> user = %{name: "Alice"}
%{name: "Alice"}
iex(2)> Map.put(user, :age, 30)
%{age: 30, name: "Alice"}
iex(3)> Map.put(user, :name, "Bob")
%{name: "Bob"}
2.3 添加键 #
elixir
iex(1)> user = %{name: "Alice"}
%{name: "Alice"}
iex(2)> Map.put(user, :age, 30)
%{age: 30, name: "Alice"}
iex(3)> Map.put_new(user, :age, 30)
%{age: 30, name: "Alice"}
iex(4)> Map.put_new(user, :name, "Bob")
%{name: "Alice"}
2.4 删除键 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> Map.delete(user, :age)
%{name: "Alice"}
三、Map模块函数 #
3.1 查询 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> Map.has_key?(user, :name)
true
iex(3)> Map.has_key?(user, :email)
false
iex(4)> Map.keys(user)
[:age, :name]
iex(5)> Map.values(user)
[30, "Alice"]
3.2 合并 #
elixir
iex(1)> Map.merge(%{a: 1}, %{b: 2})
%{a: 1, b: 2}
iex(2)> Map.merge(%{a: 1, b: 1}, %{b: 2, c: 3})
%{a: 1, b: 2, c: 3}
3.3 取值与弹出 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> Map.fetch(user, :name)
{:ok, "Alice"}
iex(3)> Map.fetch(user, :unknown)
:error
iex(4)> Map.fetch!(user, :name)
"Alice"
iex(5)> Map.pop(user, :name)
{"Alice", %{age: 30}}
iex(6)> Map.pop(user, :unknown, nil)
{nil, %{age: 30, name: "Alice"}}
3.4 转换 #
elixir
iex(1)> Map.to_list(%{a: 1, b: 2})
[a: 1, b: 2]
iex(2)> Enum.to_list(%{a: 1, b: 2})
[a: 1, b: 2]
iex(3)> Map.from_struct(%{__struct__: User, name: "Alice"})
%{name: "Alice"}
3.5 遍历 #
elixir
iex(1)> user = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> Enum.map(user, fn {k, v} -> {k, String.upcase(to_string(v))} end)
[age: "30", name: "ALICE"]
iex(3)> for {key, value} <- user, do: {key, value}
[age: 30, name: "Alice"]
四、模式匹配 #
4.1 基本匹配 #
elixir
iex(1)> %{name: name, age: age} = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> name
"Alice"
iex(3)> age
30
4.2 部分匹配 #
映射匹配只需要匹配存在的键:
elixir
iex(1)> %{name: name} = %{name: "Alice", age: 30, city: "NYC"}
%{age: 30, city: "NYC", name: "Alice"}
iex(2)> name
"Alice"
4.3 嵌套匹配 #
elixir
iex(1)> %{address: %{city: city}} = %{name: "Alice", address: %{city: "NYC", zip: "10001"}}
%{address: %{city: "NYC", zip: "10001"}, name: "Alice"}
iex(2)> city
"NYC"
4.4 动态键匹配 #
elixir
iex(1)> %{key => value} = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> key
:age
iex(3)> value
30
4.5 函数参数匹配 #
elixir
defmodule User do
def greet(%{name: name, age: age}) when age >= 18 do
"Hello, #{name}! You are an adult."
end
def greet(%{name: name}) do
"Hi, #{name}!"
end
end
五、嵌套映射 #
5.1 定义嵌套映射 #
elixir
iex(1)> user = %{
...> name: "Alice",
...> address: %{
...> city: "NYC",
...> country: "USA"
...> },
...> contacts: %{
...> email: "alice@example.com",
...> phone: "123-456-7890"
...> }
...> }
%{address: %{city: "NYC", country: "USA"}, contacts: %{email: "alice@example.com", phone: "123-456-7890"}, name: "Alice"}
5.2 访问嵌套值 #
elixir
iex(1)> user.address.city
"NYC"
iex(2)> user.contacts.email
"alice@example.com"
5.3 更新嵌套值 #
elixir
iex(1)> put_in(user.address.city, "LA")
%{address: %{city: "LA", country: "USA"}, ...}
iex(2)> update_in(user.contacts.email, &String.upcase/1)
%{contacts: %{email: "ALICE@EXAMPLE.COM", ...}, ...}
5.4 get_in/put_in/update_in #
elixir
iex(1)> get_in(user, [:address, :city])
"NYC"
iex(2)> put_in(user, [:address, :city], "LA")
%{address: %{city: "LA", country: "USA"}, ...}
iex(3)> update_in(user, [:address, :city], &String.upcase/1)
%{address: %{city: "NYC", country: "USA"}, ...}
5.5 pop_in #
elixir
iex(1)> pop_in(user, [:address, :city])
{"NYC", %{address: %{country: "USA"}, ...}}
六、映射与关键字列表 #
6.1 主要区别 #
| 特性 | 映射 | 关键字列表 |
|---|---|---|
| 键类型 | 任意 | 原子 |
| 键重复 | 不允许 | 允许 |
| 顺序 | 无序 | 有序 |
| 模式匹配 | 支持 | 有限支持 |
| 性能 | O(log n) | O(n) |
6.2 选择建议 #
- 使用映射:需要任意键类型、唯一键、快速查找
- 使用关键字列表:函数选项、有序键值对
elixir
def configure(opts) do
default = %{host: "localhost", port: 8080}
Enum.reduce(opts, default, fn {key, value}, acc ->
Map.put(acc, key, value)
end)
end
configure(port: 3000, ssl: true)
七、映射推导式 #
7.1 创建映射 #
elixir
iex(1)> for x <- 1..3, into: %{}, do: {x, x * 2}
%{1 => 2, 2 => 4, 3 => 6}
7.2 过滤转换 #
elixir
iex(1)> data = %{a: 1, b: 2, c: 3, d: 4}
%{a: 1, b: 2, c: 3, d: 4}
iex(2)> for {k, v} <- data, v > 2, into: %{}, do: {k, v * 2}
%{c: 6, d: 8}
八、映射与JSON #
8.1 编码 #
elixir
iex(1)> Jason.encode(%{name: "Alice", age: 30})
{:ok, "{\"age\":30,\"name\":\"Alice\"}"}
iex(2)> Jason.encode!(%{name: "Alice", age: 30})
"{\"age\":30,\"name\":\"Alice\"}"
8.2 解码 #
elixir
iex(1)> Jason.decode("{\"name\":\"Alice\",\"age\":30}")
{:ok, %{"age" => 30, "name" => "Alice"}}
iex(2)> Jason.decode!("{\"name\":\"Alice\",\"age\":30}")
%{"age" => 30, "name" => "Alice"}
iex(3)> Jason.decode!("{\"name\":\"Alice\",\"age\":30}", keys: :atoms)
%{age: 30, name: "Alice"}
九、性能考虑 #
9.1 小映射 #
小映射(<= 32个键)使用紧凑存储,性能接近列表。
9.2 大映射 #
大映射使用HAMT(Hash Array Mapped Trie),查找复杂度O(log n)。
9.3 最佳实践 #
elixir
user = %{name: "Alice", age: 30}
user.name
user[:name]
Map.get(user, :name, "default")
十、总结 #
本章学习了:
| 操作 | 示例 |
|---|---|
| 创建 | %{a: 1, b: 2} |
| 访问 | map.key, map[:key] |
| 更新 | %{map | key: value} |
| 添加 | Map.put(map, :key, value) |
| 删除 | Map.delete(map, :key) |
| 合并 | Map.merge(map1, map2) |
| 嵌套 | put_in(map[:a][:b], value) |
准备好学习关键字列表了吗?让我们进入下一章。
最后更新:2026-03-27