Erlang映射 #
一、映射概述 #
映射(Map)是Erlang/OTP 17引入的数据类型,用于存储键值对集合。
1.1 映射的特点 #
- 键可以是任意Erlang项
- 键值对无序存储
- 高效的查找、插入、删除
- 适合表示结构化数据
二、映射定义 #
2.1 基本定义 #
erlang
-module(map_def).
-export([demo/0]).
demo() ->
Empty = #{},
Simple = #{a => 1, b => 2, c => 3},
Mixed = #{1 => "one", "two" => 2, atom => three},
Nested = #{user => #{name => "Alice", age => 30}},
io:format("Empty: ~p~n", [Empty]),
io:format("Simple: ~p~n", [Simple]),
io:format("Mixed: ~p~n", [Mixed]),
io:format("Nested: ~p~n", [Nested]),
ok.
2.2 从列表创建 #
erlang
-module(map_from_list).
-export([demo/0]).
demo() ->
List = [{a, 1}, {b, 2}, {c, 3}],
Map = maps:from_list(List),
io:format("List: ~p~n", [List]),
io:format("Map: ~p~n", [Map]),
ok.
三、映射操作 #
3.1 获取值 #
erlang
-module(map_get).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2, c => 3},
A = maps:get(a, Map),
B = Map#{b},
Default = maps:get(d, Map, default_value),
io:format("Map: ~p~n", [Map]),
io:format("a: ~p~n", [A]),
io:format("b: ~p~n", [B]),
io:format("d (default): ~p~n", [Default]),
ok.
3.2 添加/更新值 #
erlang
-module(map_update).
-export([demo/0]).
demo() ->
Map1 = #{a => 1, b => 2},
Map2 = Map1#{c => 3},
Map3 = Map2#{a => 10},
Map4 = Map3#{d := 4},
io:format("Map1: ~p~n", [Map1]),
io:format("Map2 (add c): ~p~n", [Map2]),
io:format("Map3 (update a): ~p~n", [Map3]),
io:format("Map4 (:= syntax): ~p~n", [Map4]),
ok.
=> 与 := 的区别:
=>:添加新键或更新已有键:=:仅更新已有键(键必须存在)
3.3 删除键 #
erlang
-module(map_remove).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2, c => 3},
Map2 = maps:remove(b, Map),
io:format("Original: ~p~n", [Map]),
io:format("After remove: ~p~n", [Map2]),
ok.
3.4 检查键 #
erlang
-module(map_check).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2},
HasA = maps:is_key(a, Map),
HasC = maps:is_key(c, Map),
io:format("Map: ~p~n", [Map]),
io:format("has a: ~p~n", [HasA]),
io:format("has c: ~p~n", [HasC]),
ok.
3.5 获取键列表 #
erlang
-module(map_keys).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2, c => 3},
Keys = maps:keys(Map),
Values = maps:values(Map),
ToList = maps:to_list(Map),
io:format("Map: ~p~n", [Map]),
io:format("Keys: ~p~n", [Keys]),
io:format("Values: ~p~n", [Values]),
io:format("To list: ~p~n", [ToList]),
ok.
四、maps模块函数 #
4.1 常用函数 #
| 函数 | 说明 |
|---|---|
maps:new/0 |
创建空映射 |
maps:from_list/1 |
从列表创建 |
maps:to_list/1 |
转换为列表 |
maps:get/2 |
获取值 |
maps:get/3 |
获取值(带默认值) |
maps:put/3 |
添加/更新键值对 |
maps:remove/2 |
删除键 |
maps:is_key/2 |
检查键是否存在 |
maps:keys/1 |
获取所有键 |
maps:values/1 |
获取所有值 |
maps:size/1 |
获取大小 |
maps:merge/2 |
合并映射 |
maps:map/2 |
映射函数 |
maps:fold/3 |
折叠函数 |
maps:filter/2 |
过滤函数 |
maps:without/2 |
排除键 |
4.2 合并映射 #
erlang
-module(map_merge).
-export([demo/0]).
demo() ->
Map1 = #{a => 1, b => 2},
Map2 = #{b => 20, c => 3},
Merged = maps:merge(Map1, Map2),
io:format("Map1: ~p~n", [Map1]),
io:format("Map2: ~p~n", [Map2]),
io:format("Merged: ~p~n", [Merged]),
ok.
4.3 映射函数 #
erlang
-module(map_map).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2, c => 3},
Doubled = maps:map(fun(_K, V) -> V * 2 end, Map),
io:format("Original: ~p~n", [Map]),
io:format("Doubled: ~p~n", [Doubled]),
ok.
4.4 折叠函数 #
erlang
-module(map_fold).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2, c => 3},
Sum = maps:fold(fun(_K, V, Acc) -> V + Acc end, 0, Map),
Keys = maps:fold(fun(K, _V, Acc) -> [K | Acc] end, [], Map),
io:format("Map: ~p~n", [Map]),
io:format("Sum: ~p~n", [Sum]),
io:format("Keys: ~p~n", [Keys]),
ok.
4.5 过滤函数 #
erlang
-module(map_filter).
-export([demo/0]).
demo() ->
Map = #{a => 1, b => 2, c => 3, d => 4, e => 5},
Evens = maps:filter(fun(_K, V) -> V rem 2 =:= 0 end, Map),
io:format("Original: ~p~n", [Map]),
io:format("Evens: ~p~n", [Evens]),
ok.
五、映射模式匹配 #
5.1 基本匹配 #
erlang
-module(map_pattern).
-export([demo/0]).
demo() ->
#{a := A, b := B} = #{a => 1, b => 2, c => 3},
io:format("A=~p, B=~p~n", [A, B]),
ok.
5.2 函数参数匹配 #
erlang
-module(map_func_match).
-export([greet/1]).
greet(#{name := Name, age := Age}) ->
io:format("Hello ~s, you are ~p years old~n", [Name, Age]);
greet(#{name := Name}) ->
io:format("Hello ~s~n", [Name]);
greet(_) ->
io:format("Hello stranger~n").
5.3 匹配特定键 #
erlang
-module(match_specific_key).
-export([handle/1]).
handle(#{type := user, name := Name}) ->
{user, Name};
handle(#{type := admin, name := Name, level := Level}) ->
{admin, Name, Level};
handle(#{type := Type}) ->
{unknown, Type}.
5.4 匹配嵌套映射 #
erlang
-module(nested_map_match).
-export([demo/0]).
demo() ->
User = #{
name => "Alice",
address => #{
city => "Beijing",
country => "China"
}
},
#{name := Name, address := #{city := City}} = User,
io:format("Name: ~p~n", [Name]),
io:format("City: ~p~n", [City]),
ok.
六、实际应用 #
6.1 配置管理 #
erlang
-module(config_map).
-export([get/2, set/3, default/0]).
default() ->
#{
host => "localhost",
port => 8080,
timeout => 5000,
debug => false
}.
get(Key, Config) ->
maps:get(Key, Config).
set(Key, Value, Config) ->
Config#{Key => Value}.
6.2 用户数据 #
erlang
-module(user_map).
-export([new/3, update_age/2, to_list/1]).
new(Name, Age, Email) ->
#{
name => Name,
age => Age,
email => Email,
created_at => erlang:timestamp()
}.
update_age(NewAge, User) ->
User#{age := NewAge}.
to_list(User) ->
maps:to_list(User).
6.3 HTTP请求 #
erlang
-module(http_request).
-export([new/2, add_header/3, set_body/2]).
new(Method, Url) ->
#{
method => Method,
url => Url,
headers => #{},
body => <<>>
}.
add_header(Name, Value, Request) ->
Headers = maps:get(headers, Request),
Request#{headers := Headers#{Name => Value}}.
set_body(Body, Request) ->
Request#{body := Body}.
6.4 缓存系统 #
erlang
-module(cache_map).
-export([new/0, get/2, put/3, delete/2, size/1]).
new() -> #{}.
get(Key, Cache) ->
case maps:find(Key, Cache) of
{ok, Value} -> {ok, Value};
error -> not_found
end.
put(Key, Value, Cache) ->
Cache#{Key => Value}.
delete(Key, Cache) ->
maps:remove(Key, Cache).
size(Cache) ->
maps:size(Cache).
七、映射与记录比较 #
7.1 使用映射 #
erlang
-module(map_vs_record).
-export([map_example/0, record_example/0]).
-record(person, {name, age}).
map_example() ->
Person = #{name => "Alice", age => 30},
Name = maps:get(name, Person),
Age = maps:get(age, Person),
{Name, Age}.
record_example() ->
Person = #person{name = "Alice", age = 30},
Name = Person#person.name,
Age = Person#person.age,
{Name, Age}.
7.2 比较表 #
| 特性 | 映射 | 记录 |
|---|---|---|
| 动态键 | 支持 | 不支持 |
| 模式匹配 | 部分支持 | 完全支持 |
| 编译时检查 | 无 | 有 |
| 内存效率 | 较低 | 较高 |
| 适用场景 | 动态数据 | 固定结构 |
八、性能考虑 #
8.1 小映射优化 #
erlang
-module(map_perf).
-export([demo/0]).
demo() ->
Small = #{a => 1, b => 2},
Large = maps:from_list([{X, X} || X <- lists:seq(1, 100)]),
io:format("Small map size: ~p~n", [maps:size(Small)]),
io:format("Large map size: ~p~n", [maps:size(Large)]),
ok.
8.2 更新操作 #
erlang
-module(map_update_perf).
-export([demo/0]).
demo() ->
Map = #{a => 1},
Map2 = Map#{b => 2},
Map3 = Map2#{a := 10},
io:format("Map: ~p~n", [Map]),
io:format("Map2: ~p~n", [Map2]),
io:format("Map3: ~p~n", [Map3]),
ok.
九、实用函数 #
9.1 深度合并 #
erlang
-module(deep_merge).
-export([merge/2]).
merge(Map1, Map2) when is_map(Map1), is_map(Map2) ->
maps:fold(
fun(K, V2, Acc) ->
case maps:find(K, Acc) of
{ok, V1} when is_map(V1), is_map(V2) ->
Acc#{K := merge(V1, V2)};
_ ->
Acc#{K => V2}
end
end,
Map1,
Map2
).
9.2 深度获取 #
erlang
-module(deep_get).
-export([get/2]).
get([], Map) -> Map;
get([Key | Rest], Map) when is_map(Map) ->
case maps:find(Key, Map) of
{ok, Value} -> get(Rest, Value);
error -> undefined
end;
get(_, _) -> undefined.
9.3 键转换 #
erlang
-module(key_transform).
-export([keys_to_atoms/1, keys_to_strings/1]).
keys_to_atoms(Map) ->
maps:from_list([{to_atom(K), V} || {K, V} <- maps:to_list(Map)]).
keys_to_strings(Map) ->
maps:from_list([{to_string(K), V} || {K, V} <- maps:to_list(Map)]).
to_atom(K) when is_atom(K) -> K;
to_atom(K) when is_binary(K) -> binary_to_atom(K, utf8);
to_atom(K) when is_list(K) -> list_to_atom(K).
to_string(K) when is_binary(K) -> K;
to_string(K) when is_atom(K) -> atom_to_binary(K, utf8);
to_string(K) when is_list(K) -> list_to_binary(K).
十、总结 #
本章学习了:
- 映射的定义和特点
- 映射操作函数
- maps模块函数
- 映射模式匹配
- 实际应用案例
- 映射与记录比较
- 性能考虑
- 实用函数
准备好学习记录类型了吗?让我们进入下一章。
最后更新:2026-03-27