主要是遇到 Map匹配的問題,所以順便回憶一下 Erlang 中的映射組 Map,在其它語言中被稱作 Hash 哈希或者 Dict 字典。
Erlang 從 R17 版本開始支持映射組
創(chuàng)建映射組
Erlang 中的映射組用結(jié)構(gòu) #{} 表示,創(chuàng)建一個映射組可以這樣
% 也可以創(chuàng)建一個空的映射組
#{}.
% => #{}
更新映射組
映射組可以更新,所謂的更新是創(chuàng)建一個新的映射組,因為 Erlang 中的變量是不可改變的。
% 過年啦,又長一歲了,變成嶄新的我啦
NewMe = Me#{ age => 20 }.
% => #{age => 20,name => "wittyfox"}
% 當(dāng)然也可以直接修改
#{ name => "wittyfox", age => 19 }#{ age => 20 }.
% => #{age => 20,name => "wittyfox"}
=> 用于創(chuàng)建或更新一個映射,如果鍵存在,則更新它,否則就創(chuàng)建一個新的映射。如果一不小心某個鍵拼寫錯誤,Oops.
% 只能更新已存在的映射
Me#{ age := 20 }.
% => #{age => 20,name => "wittyfox"}
兩種操作符的區(qū)別
1.=> 可以用來更新映射或者創(chuàng)建新的映射
2.:= 只能更新映射,在鍵不存在時會拋出異常
所以有下面的總結(jié)
創(chuàng)建映射組時
只能使用 =>,:= 只能更新映射而無法創(chuàng)建新的映射,而創(chuàng)建映射組時需要創(chuàng)建若干映射
左邊只能使用 :=,=> 在鍵不存在時可以創(chuàng)建新的映射,而映射組匹配可以部分匹配 (只匹配左邊擁有的部分) ,所以匹配是沒有意義的
% Age.
% => 19
% 不合法的匹配
#{ age => Age } = Me.
% * 1: illegal pattern
只在創(chuàng)建映射組或明確需要創(chuàng)建新的映射時使用 =>,而在其它場合均使用 :=
% 這里是匹配,只能使用 :=
show({?MODULE, #{name := Name, age := Age}}) ->
io:format("Name: ~p, Age: ~p~n", [Name, Age]).
上面的更新映射,創(chuàng)建新的映射以及匹配可以同時針對多個映射,這里只是作為例子而只選擇一對映射。
映射組操作
Erlang 中的 maps 模塊用于操作映射組
映射組的創(chuàng)建及屬性
% 返回所有鍵
maps:keys(Me).
% => [age,name]
% 判斷是否存在鍵
maps:is_key(age, Me).
% => true
maps:is_key(aeg, Me).
% => false
% 按鍵的順序返回所有值
maps:values(Me).
% =>[19,"wittyfox"]
% 映射數(shù)量
maps:size(Me).
% => 2
% 還可以使用 erlang:map_size/1
% 此函數(shù)可以用于 Guard,maps 模塊內(nèi)部也是使用此函數(shù)的
map_size(Me).
% => 2
映射的增加、刪除、獲取
% maps:get/3 在鍵不存在時會返回第三個參數(shù)的值
maps:get(aeg, Me, 20).
% => 20
% 用于更新或創(chuàng)建映射,類似于 =>
% 所謂更新,只是返回更新后的新的映射組,原映射組并不會改變
maps:put(gender, male, Me).
% => #{age => 19,gender => male,name => "wittyfox"}
% 用于更新映射,類似于 :=,鍵不存在時會拋出 badarg 異常
maps:update(age, 20, Me).
% => #{age => 20,name => "wittyfox"}
% 刪除一個映射,鍵不存在時相當(dāng)于什么都沒做,不會拋出異常
maps:remove(age, Me).
% => #{name => "wittyfox"}
% 查找鍵的值,鍵不存在時返回 error
maps:find(age, Me).
% => {ok, 19}
maps:find(aeg, Me).
% => error
映射組的歸并
% 相當(dāng)于
Me#{ age => 10 }.
映射組與列表之間的轉(zhuǎn)換
% 從列表構(gòu)建映射組
maps:from_list([]).
% => #{}
maps:from_list([{name, "wittyfox"}, {age, 19}]).
% => #{age => 19,name => "wittyfox"}
映射組的遍歷
% X, Y 分別為一對映射的鍵和值,V 為上一次迭代的結(jié)果,0 為迭代的初始值
% 這里簡單的用于每次迭代時值加 1,結(jié)果就是映射組的映射數(shù)量
maps:fold(fun (X, Y, V) -> V + 1 end, 0, Me).
% => 2
映射組中映射的選取
返回第一個參數(shù)中指定的鍵的映射組成的映射組
maps:with([age], Me).
% => #{age => 19}
% 鍵可以不存在
maps:with([aeg], Me).
% => #{}
maps:without([age], Me).
% => #{name => "wittyfox"}
% 鍵也可以不存在
maps:without([age, neme], Me).
% => #{name => "wittyfox"}
值得一提的是 maps 模塊中的若干函數(shù),比如 map, fold, with 和 without 都是使用 maps:to_list/1 轉(zhuǎn)到列表,然后使用 lists 模塊的工具處理,然后使用 maps:from_list/1 轉(zhuǎn)回到映射組的。