Erlang中的映射组Map详细介绍(二郎)一篇读懂

随心笔谈9个月前发布 admin
211 00
🌐 经济型:买域名、轻量云服务器、用途:游戏 网站等 《腾讯云》特点:特价机便宜 适合初学者用 点我优惠购买
🚀 拓展型:买域名、轻量云服务器、用途:游戏 网站等 《阿里云》特点:中档服务器便宜 域名备案事多 点我优惠购买
🛡️ 稳定型:买域名、轻量云服务器、用途:游戏 网站等 《西部数码》 特点:比上两家略贵但是稳定性超好事也少 点我优惠购买

文章摘要

这篇文章主要介绍了Erlang中的映射组(即哈希表或字典)及其相关操作。以下是总结: 1. **映射组的基本操作** - 使用`#{}`结构创建映射组,例如`#{name:"wittyfox", age:19}`。 - 更新映射组时,使用`=>`操作符,可以同时更新或创建新的映射。 2. **操作符的区别** - `=>`用于更新映射或创建新的映射。 - `:=`只能更新已存在的映射,键不存在时会抛出`badarg`异常。 - 在创建映射组时,使用`=>`;在映射组匹配时,使用`:=`。 3. **映射组匹配** - 使用`=`操作符匹配映射组,`=>`匹配后会部分匹配键,但没有意义。 - 匹配时,最好使用`:=`,并在创建映射组时使用`=>`。 4. **映射组操作函数** - `maps:get/2`:键不存在时抛出异常;键存在时返回值。 - `maps:put/3`:类似于`=>`,键不存在时返回默认值。 - `maps:update/2`:更新键的值,键不存在时抛出异常。 - `maps:remove/2`:删除键,键不存在时无操作。 - `maps:find/2`:查找键,键不存在时抛出异常。 5. **映射组的归并与转换** - 使用`maps:merge/2`归并两个映射组。 - 使用`maps:to_list/1`将映射组转换为列表。 - 使用`maps:from_list/1`将列表转换为映射组。 6. **映射组的遍历与选取** - 使用`maps:map/2`遍历映射组,执行指定操作。 - 使用`maps:with/2`选取特定键的映射。 - 使用`maps:without/2`移除特定键的映射。 7. **注意事项** - 在处理映射组时,使用`maps`模块中的函数,这些函数通过`to_list`和`from_list`将映射组转换为列表进行处理。 - 在使用`fold`函数时,初始值为0,可以用于统计映射数量。 这篇文章通过具体的代码示例,详细说明了Erlang中映射组的操作方法及其注意事项,强调了操作符的选择对程序行为的影响。



主要是遇到 Map匹配的问题,所以顺便回忆一下 Erlang 中的映射组 Map,在其它语言中被称作 Hash 哈希或者 Dict 字典。

Erlang 从 R17 版本开始支持映射组

创建映射组

Erlang 中的映射组用结构 #{} 表示,创建一个映射组可以这样

复制代码 代码如下:

% 不管你怎么排序,最终结果都是按键的字典顺序排列的

#{ name=> “wittyfox”, age=> 19 }.

%=> #{age=> 20,name=> “wittyfox”}

% 也可以创建一个空的映射组

#{}.

%=> #{}

更新映射组

映射组可以更新,所谓的更新是创建一个新的映射组,因为 Erlang 中的变量是不可改变的。

复制代码 代码如下:

% 现在的我

Me=#{ name=> “wittyfox”, age=> 19 }.

%=> #{age=> 19,name=> “wittyfox”}

% 过年啦,又长一岁了,变成崭新的我啦

NewMe=Me#{ age=> 20 }.

%=> #{age=> 20,name=> “wittyfox”}

% 当然也可以直接修改

#{ name=> “wittyfox”, age=> 19 }#{ age=> 20 }.

%=> #{age=> 20,name=> “wittyfox”}

=> 用于创建或更新一个映射,如果键存在,则更新它,否则就创建一个新的映射。如果一不小心某个键拼写错误,Oops.

复制代码 代码如下:

% 本来想更新 age,结果一不小心拼写错误,创建了一个新的映射

Me#{ aeg=> 20 }.

%=> #{aeg=> 20,age=> 19,name=> “wittyfox”}.

为了避免这种情况,还有一种更新映射的方法,使用 :=,它只能用来更新映射,而不能创建新的映射,如果键不存在,就会抛出一个 badarg 异常。

复制代码 代码如下:

% 不存在 aeg 键,抛出 badarg 异常

Me#{ aeg :=20 }.

% ** exception error: bad argument … blabla

% 只能更新已存在的映射

Me#{ age :=20 }.

%=> #{age=> 20,name=> “wittyfox”}

两种操作符的区别

1.=> 可以用来更新映射或者创建新的映射

2.:=只能更新映射,在键不存在时会抛出异常

所以有下面的总结

创建映射组时

只能使用=>,:=只能更新映射而无法创建新的映射,而创建映射组时需要创建若干映射

复制代码 代码如下:

#{ name :=”wittyfox”, age :=19 }.

% * 1: only association operators ‘=>’ are allowed in map construction

映射组匹配的

左边只能使用 :=,=> 在键不存在时可以创建新的映射,而映射组匹配可以部分匹配 (只匹配左边拥有的部分) ,所以匹配是没有意义的

复制代码 代码如下:

% 部分匹配: 我们只想取出 age,所以我们只关心参数中有没有 age 这个映射

#{ age :=Age }=Me.

%=> #{age=> 19,name=> “wittyfox”}

% Age.

%=> 19

% 不合法的匹配

#{ age=> Age }=Me.

% * 1: illegal pattern

为了更好的发现错误

只在创建映射组或明确需要创建新的映射时使用=>,而在其它场合均使用 :=

复制代码 代码如下:

 % 这里是创建映射组,只能使用=>

 new() ->

     {ok, {?MODULE, #{name=> “wittyfox”, age=> 19}}}.

 % 这里是匹配,只能使用 :=

 show({?MODULE, #{name :=Name, age :=Age}}) ->

     io:format(“Name: ~p, Age: ~p~n”, [Name, Age]).

注意

上面的更新映射,创建新的映射以及匹配可以同时针对多个映射,这里只是作为例子而只选择一对映射。

映射组操作

Erlang 中的 maps 模块用于操作映射组

映射组的创建及属性

复制代码 代码如下:

% 创建映射组

maps:new().

%=> #{}

% 返回所有键

maps:keys(Me).

%=> [age,name]

% 判断是否存在键

maps:is_key(age, Me).

%=> true

maps:is_key(aeg, Me).

%=> false

% 按键的顺序返回所有值

maps:values(Me).

%=>[19,”wittyfox”]

% 映射数量

maps:size(Me).

%=> 2

% 还可以使用 erlang:map_size/1

% 此函数可以用于 Guard,maps 模块内部也是使用此函数的

map_size(Me).

%=> 2

映射的增加、删除、获取

复制代码 代码如下:

% maps:get/2 在键不存在时会抛出异常

maps:get(age, Me).

%=> 19

% maps:get/3 在键不存在时会返回第三个参数的值

maps:get(aeg, Me, 20).

%=> 20

% 用于更新或创建映射,类似于=>

% 所谓更新,只是返回更新后的新的映射组,原映射组并不会改变

maps:put(gender, male, Me).

%=> #{age=> 19,gender=> male,name=> “wittyfox”}

% 用于更新映射,类似于 :=,键不存在时会抛出 badarg 异常

maps:update(age, 20, Me).

%=> #{age=> 20,name=> “wittyfox”}

% 删除一个映射,键不存在时相当于什么都没做,不会抛出异常

maps:remove(age, Me).

%=> #{name=> “wittyfox”}

% 查找键的值,键不存在时返回 error

maps:find(age, Me).

%=> {ok, 19}

maps:find(aeg, Me).

%=> error

映射组的归并

复制代码 代码如下:

% 归并两个映射组,注意第二个参数是创建新的映射组,所以只能用=>

maps:merge(Me, #{ age=> 10 }).  

%=> #{age=> 10,name=> “wittyfox”}

% 相当于

Me#{ age=> 10 }.

映射组与列表之间的转换

复制代码 代码如下:

% 返回映射元组对的列表

maps:to_list(Me).

%=> [{age,19},{name,”wittyfox”}]

% 从列表构建映射组

maps:from_list([]).

%=> #{}

maps:from_list([{name, “wittyfox”}, {age, 19}]).

%=> #{age=> 19,name=> “wittyfox”}

映射组的遍历

复制代码 代码如下:

% 对映射组的每对映射执行操作

% X, Y 分别为一对映射的键和值

maps:map(fun (X, Y) -> io:format(“~p=> ~p~n”, [X, Y]) end, Me). 

% age=> 19                                             % 输出

% name=> “wittyfox”                                    % 输出

%=> #{age=> ok,name=> ok}                            % 返回值

% X, Y 分别为一对映射的键和值,V 为上一次迭代的结果,0 为迭代的初始值

% 这里简单的用于每次迭代时值加 1,结果就是映射组的映射数量

maps:fold(fun (X, Y, V) -> V + 1 end, 0, Me).

%=> 2

映射组中映射的选取

返回第一个参数中指定的键的映射组成的映射组

复制代码 代码如下:

maps:with([], Me).

%=> #{}

maps:with([age], Me).

%=> #{age=> 19}

% 键可以不存在

maps:with([aeg], Me).

%=> #{}

返回键不再第一个参数的列表中的映射组成的映射组

复制代码 代码如下:

maps:without([], Me).

%=> #{age=> 19,name=> “wittyfox”}

maps:without([age], Me).

%=> #{name=> “wittyfox”}

% 键也可以不存在

maps:without([age, neme], Me).

%=> #{name=> “wittyfox”}

注意

值得一提的是 maps 模块中的若干函数,比如 map, fold, with 和 without 都是使用 maps:to_list/1 转到列表,然后使用 lists 模块的工具处理,然后使用 maps:from_list/1 转回到映射组的。

© 版权声明

相关文章