Erlang中的映射组Map详细介绍_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 转回到映射组的。

时间: 2024-11-01 07:17:04

Erlang中的映射组Map详细介绍_Erlang的相关文章

Erlang中的函数与流程控制介绍_Erlang

一:函数 1:在Erlang中,[名字相同但参数数目不同]的两个函数是完全不同的函数. 2:其他模块内的函数用完全限定名称 被调用: 复制代码 代码如下: -module(sort1). -export([reverse_sort/1, sort/1]). reverse_sort(L) ->         lists1:reverse(sort(L)). sort(L) ->         lists:sort(L). 3:子句间以分号[;]分隔,在最后的结尾处以[.]结尾. 4:每个函

JavaScript中的分号插入机制详细介绍

 这篇文章主要介绍了JavaScript中的分号插入机制详细介绍,本文讲解JavaScript中各种情况下的分号插入机制,需要的朋友可以参考下     仅在}之前.一个或多个换行之后和程序输入的结尾被插入 也就是说你只能在一行.一个代码块和一段程序结束的地方省略分号. 也就是说你可以写如下代码 代码如下: function square(x) { var n = +x return n * n } 但是却不可以写的像下面代码一样,这样就报错了哦 代码如下: function area(r) {

Android中imageview.ScaleType使用方法详细介绍

Android中imageview.ScaleType使用方法详细介绍 ScaleType属性用以表示显示图片的方式,共有8种取值: ScaleType.CENTER:图片大小为原始大小,如果图片大小大于ImageView控件,则截取图片中间部分,若小于,则直接将图片居中显示. ScaleType.CENTER_CROP:将图片等比例缩放,让图像的短边与ImageView的边长度相同,即不能留有空白,缩放后截取中间部分进行显示. ScaleType.CENTER_INSIDE:将图片大小大于Im

中华通网络电话使用的详细介绍

  中国大陆内电话怎么收费? 1.零月租,全球无漫游.无论在全球哪个国家/地区拨打国内电话0.09元/分钟,充值后资费低至0.05元/分钟,支持拨打国内手机.座机.小灵通.(使用中华通软件拨打电话时,只从中华通账户中扣取费用,不会额外收取网络.电话接通.线路租用等其它费用) 2.只收取主叫方费用,被叫由当地运营商而定:如固话.小灵通接听电话免费的,当地手机如有接听免费业务则接听中华通免费,不会产生其他的费用. 国际长途怎么收费? 1.拨打不同的国家/地区资费不同,各个国家/地区不同号段的号码资费

【IOS-COCOS2D-X 游戏开发之十四】XCODE中C++&OBJECT-C混编,详细介绍如何在COCOS2DX中访问OBJECT函数以及APPLE API

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2dx/743.html Cocos2dx系列博文的上一篇详细介绍了如何在Xcode中利用jni调用Android的Java层代码,还没有看过的童鞋,请移步到如下博文: [iOS-cocos2d-X 游戏开发之十三]详细讲解在Xcode中利用预编译并通过Jni调用Android的Java层代码(cocos2dx里访问调用

PhotoShop中Lab模式调色理论详细介绍

本例向朋友们介绍在PS的LAB模式下调色的原理以及通过实例来详细讲解LAB模式计算调色的运用, 希望能给对PS调色感兴趣的朋友带来帮助~~ 现在来说说计算这个话题,这是个大题目,要一下子说清楚这个,要花不少的时间,所以用闲谈这个方 式可以随便就这个聊聊. 在说清楚这个之前,先了解下什么是Lab模.这个模式是不依赖于光线和颜料,在理论上包括人眼可以看 见的所有色彩模式.简单地说,就是模仿人眼视角习惯而产生的模式. "Lab 中的数值描述正常视力的人能够看到的所有颜色.因为 Lab 描述颜色的显示方

Windows系统中IIS防盗链设置详细介绍

首页我们安装一个组件:isapi.msi 安装完后,对软件安装目录的IIS_WGP组的读写权限(重要,如果不设置安装完后你的网站就会直接Service Unavailable,无法访问). 假如你的安装目录是D:Program FilesHeliconISAPI_Rewrite(默认安装目录是Program FilesHeliconISAPI_Rewrite,我们可以先建立),右击ISAPI_Rewrite,选择"属性"->"安 全"->"添加

Java中的静态绑定和动态绑定详细介绍_java

一个Java程序的执行要经过编译和执行(解释)这两个步骤,同时Java又是面向对象的编程语言.当子类和父类存在同一个方法,子类重写了父类的方法,程序在运行时调用方法是调用父类的方法还是子类的重写方法呢,这应该是我们在初学Java时遇到的问题.这里首先我们将确定这种调用何种方法实现或者变量的操作叫做绑定. 在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定.另一种就是动态绑定,亦称为后期绑定. 区别对比 1.静态绑定发生在编译时期,动态绑定发生在运行时 2.使用private或stati

mysql中show指令使用方法详细介绍_Mysql

本文主要介绍mysql数据库下show命令的主要用法 a. show tables或show tables from database_name; -- 显示当前数据库中所有表的名称. b. show databases; -- 显示mysql中所有数据库的名称. c. show columns from table_name from database_name; 或show columns from database_name.table_name; -- 显示表中列名称. d. show