erlang有两种复合结构。tuple和list,两者的区别是tuple子元素的个数是固定不变的。声明后就不能改变了。而list是可变的,能够通过[H|T]来取出或插入新元素。

record有点像C/C++里面的结构体。实际上是语法糖,方便我们的开发。代码汇编时转成tuple表达形式。

Tuple

tuple的表示方法如:

  1. {Term1,...,TermN}

以下以样例说明erlang tuple及一些基本操作:

  1. 1> A = {1,2}.
  2. {1,2}
  3. 2> tuple_size(A).
  4. 2
  5. 3> is_tuple(A).
  6. true
  7. 4> tuple_to_list(A).
  8. [1,2]
  9. 5> element(1, A).
  10. 1
  11. 6> setelement(2, A, 3).
  12. {1,3}

Record

record有点像C/C++里面的结构体。表示方法如:

  1. -record(Name, {Field1 [= Value1],
  2. ...
  3. FieldN [= ValueN]}).

以下以样例说明erlang record及一些基本操作:

  1. %% shell下定义 record结构 person
  2. %% 等效程序里定义 -record(person, {name, age}).
  3. 7> rd(person, {name, age}).
  4. person
  5. 8> A1 = #person{name = "john", age = 10}.
  6. #person{name = "john",age = 10}
  7. 9> A2 = A1#person{name = "Lucy"}.
  8. #person{name = "Lucy",age = 10}
  9.  
  10. %% record 一次赋值
  11. 10> X = #person{_ = 1}.
  12. #person{name = 1,age = 1}
  13. 11> element(2, X).
  14. 1
  15. 12> setelement(2, X, "Tom").
  16. #person{name = "Tom",age = 1}
  1. 14> P=#person{}.
  2. #person{name = undefined,age = undefined}
  3. 15> is_record(P,person).
  4. true
  5. 16> #person.age.
  6. 3
  7. 17> #person.name.
  8. 2

tuple 和 record 有什么关系?

record仅仅是语言程序上的结构,方便我们的开发,在erlang编译的时候会转成tuple处理

  1. %% shell下定义 record结构 person2
  2. %% 等效程序里定义 -record(person2, {name = "", age = 1}).
  3. 23> rd(person2, {name = "", age = 1}).
  4. person2
  5. 24> A3 = #person2{name = "Jimmy"}.
  6. #person2{name = "Jimmy",age = 1}
  7.  
  8. %% 模式匹配
  9. 25> {_, Name, _} = A3.
  10. #person2{name = "Jimmy",age = 0}
  11. 26> Name.
  12. "Jimmy"
  13. 27> #person2{name = Name2} = A3.
  14. #person2{name = "Jimmy",age = 0}
  15. 28> Name2.
  16. "Jimmy"

以下,以一个简单的样例,測试tuple和record的汇编代码

  1. -module(test).
  2.  
  3. -export([test/0]).
  4.  
  5. -record(person, {name, age}).
  6.  
  7. test() ->
  8. A = {person, "Tom", 1},
  9. B = #person{name = "Tom", age = 1},
  10. {A,B}.

通过命令erlc -S test.erl 能够生成 test.S的汇编代码

{function, test, 0, 2}.
  {label,1}.
    {line,[{location,"c:/test.erl",7}]}.
    {func_info,{atom,test},{atom,test},0}.
  {label,2}.
    {move, {literal, { {person,"Tom",1} ,{person,"Tom",1}} }, {x,0} }.
    return.

record_info/2

说到record,不得不提record_info/2,这个函数用以获取record的信息,原型:

record_info(Type, Record) ->  integer() | list

Type有两种:size、fields

  1. 34> rd(person,{id, name}).
  2. person
  3. 35> record_info(fields, person).
  4. [id,name]
  5. 36> record_info(size, person).
  6. 3

record_info/2实际上一个语法糖。写个样例tt.erl说明一下:

  1. -module(tt).
  2. -compile(export_all).
  3.  
  4. -record(person,{id, name, age}).
  5. fields() ->
  6. record_info(fields, person).
  7.  
  8. size() ->
  9. record_info(size, person).

erlc -S tt.erl

编译这个模块得到 tt.S,这是当中的汇编码:

{function, fields, 0, 2}.
  {label,1}.
    {line,[{location,"tt.erl",5}]}.
    {func_info,{atom,tt},{atom,fields},0}.
  {label,2}.
    {move,{literal, [id,name,age] },{x,0}}.
    return.

{function, size, 0, 4}.
  {label,3}.
    {line,[{location,"tt.erl",8}]}.
    {func_info,{atom,tt},{atom,size},0}.
  {label,4}.
    {move, {integer,4} ,{x,0}}.
    return.

在编译期就直接被erlang优化了

改动tuple结构

R16以后。erlang提供了2个接口用于改动tuple结构。
1、添加tuple元素
erlang:append_element(Tuple1, Term)
> erlang:append_element({one, two}, three).
{one,two,three}

等效于 list_to_tuple(tuple_to_list(Tuple1) ++ [Term]),但性能比后者高

2、移除tuple元素
erlang:delete_element(Index, Tuple1)
> erlang:delete_element(2, {one, two, three}).
{one,three}

record 的模式匹配

record有两种模式匹配的方法:

  1. 1> rd(person, {a,b}).
  2. person
  3. 2> case #person{a=10} of #person{a=A} -> A; _ -> false end.
  4. 10
  5. 3> A.
  6. 10
  7. 4> #person{a=B} = #person{a=15}.
  8. #person{a = 15,b = undefined}
  9. 5> B.
  10. 15

如今,顺道讨论下 record 模式匹配的本质。

  1. 1> rd(person, {a,b}).
  2. person
  3. 2> #person{} =:= #person{a=1}.
  4. false
  5. 3> case #person{a=1} of #person{} -> true; _ -> false end.
  6. true
  7. 4> #person{} = #person{a=1}.
  8. #person{a = 1,b = undefined}

前面说到 record在执行期会编译成tuple,所以第2点是推断两个tuple是否同样。

而第3点和第4点本质区别不大,仅仅是执行了模式匹配,检查tuple是否 3 个元素。且第一个元素是原子person,不会推断除其它元素值是否相等。可是假设像以下这样写就会匹配到其它元素了。

  1. 5> case #person{a=1} of #person{a=3} -> true; _ -> false end.
  2. false
  3. 6> #person{a=3} = #person{a=1}.
  4. ** exception error: no match of right hand side value #person{a = 1,b = undefined}

有兴趣的同学參照上面打印erlang模块汇编码就能够找到答案了。

更新说明:
2014/10/30 补充了record函数 record_info/2的说明
2014/11/06 补充了record函数is_record/2等基本操作
2015/2/11  补充了两个tuple结构改动函数
2015/3/4  补充了record的模式匹配

參考:http://blog.csdn.net/mycwq/article/details/31421341

说说erlang tuple和record结构的更多相关文章

  1. Erlang中的record与宏

    http://www.cnblogs.com/me-sa/archive/2011/07/20/erlang0006.html 在Erlang中使用Tuple ,数据项的顺序\数量都是确定的,一旦数据 ...

  2. Erlang--etc结构解析

    Erlang中可以用List表达集合数据,但是如果数据量特别大的话在List中访问元素就会变慢了;这种主要是由于List的绝大部分操作都是基于遍历完成的. Erlang的设计目标是软实时(参考:htt ...

  3. Erlang ETS Table

    不需要显示用锁,插入和查询时间不仅快而且控制为常量,这就是Erlang的ETS Table. 为什么而设计? Erlang中可以用List表达集合数据,但是如果数据量特别大的话在List中访问元素就会 ...

  4. [Erlang 0117] 当我们谈论Erlang Maps时,我们谈论什么 Part 2

    声明:本文讨论的Erlang Maps是基于17.0-rc2,时间2014-3-4.后续Maps可能会出现语法或函数API上的有所调整,特此说明. 前情提要: [Erlang 0116] 当我们谈论E ...

  5. [Erlang 0116] 当我们谈论Erlang Maps时,我们谈论什么 Part 1

         Erlang 增加 Maps数据类型并不是很突然,因为这个提议已经进行了2~3年之久,只不过Joe Armstrong老爷子最近一篇文章Big changes to Erlang掀起不小了风 ...

  6. 当我们谈论Erlang Maps时,我们谈论什么 Part 2

    声明:本文讨论的Erlang Maps是基于17.0-rc2,时间2014-3-4.兴许Maps可能会出现语法或函数API上的有所调整,特此说明. 前情提要: [Erlang 0116] 当我们谈论E ...

  7. 当我们谈论Erlang Maps时,我们谈论什么 Part 1

         Erlang 添加 Maps数据类型并非非常突然,由于这个提议已经进行了2~3年之久,仅仅只是Joe Armstrong老爷子近期一篇文章Big changes to Erlang掀起不小了 ...

  8. Erlang 初学者技巧及避免的陷阱

    1. 传参或在匿名函数内慎用self() 通常在做消息传递或新建进程的时候我们需要将当前进程的Pid发给目标进程以便接收返回信息,但初学者不留意容易犯以下错误 spawn(fun() -> lo ...

  9. Erlang 进程被抢占的条件——一个进程长时霸占调度器的极端示例

    最近研究 binary 的实现和各种操作对应的 beam 虚拟机汇编指令,发现有一些指令序列是不可重入的,比如说有的指令构造一个上下文(也就是某种全局状态),然后下一条指令会对这个上下文做操作(具体的 ...

随机推荐

  1. window下配置SSH连接GitHub、GitHub配置ssh key

    window下配置SSH连接GitHub.GitHub配置ssh key   此经验分两部分: 第一部分介绍:在windows下通过msysGit(Git for windows.Git Bash)配 ...

  2. Codeforces 1027D Mouse Hunt (强连通缩点 || DFS+并查集)

    <题目链接> 题目大意: 有n个房间,每个房间都会有一只老鼠.处于第i个房间的老鼠可以逃窜到第ai个房间中.现在要清理掉所有的老鼠,而在第i个房间中防止老鼠夹的花费是ci,问你消灭掉所有老 ...

  3. hdu 1518 Square 木棍建正方形【DFS】

    题目链接 题目大意: 题意就是输入棍子的数量和每根棍子的长度,看能不能拼成正方形. #include <bits/stdc++.h> using namespace std; int n, ...

  4. redis初步入门(2)

    一.redis持久化 1.redis是一个内存数据库,当redis服务器重启,或者电脑关机重启,数据会丢失,所以需要将redis内存中的数据持久化保存到硬盘文件中. 2.redis持久化机制 (1)R ...

  5. EF Core中Fluent Api如何删除指定数据表中的行

    这两天一直在研究在code first下如何删除数据表中的指定行,于是开始搜狗,后来百度,压根就找不到资料,后来一想可能我的搜索关键字有问题,而且ef core命令与ef的命令差不多,于是从这两个方面 ...

  6. VeeamBackup9.5安装与配置

    产品介绍 Veeam是一家第三方的虚拟化数据中心备份及恢复公司,主要软件为Veeam Availability Suite,包括Veeam Backup & Replication和Veeam ...

  7. Codeforces.449D.Jzzhu and Numbers(容斥 高维前缀和)

    题目链接 \(Description\) 给定\(n\)个正整数\(a_i\).求有多少个子序列\(a_{i_1},a_{i_2},...,a_{i_k}\),满足\(a_{i_1},a_{i_2}, ...

  8. Navicat Premium for Mac的破解教程

          Navicat Premium for Mac破解教程 https://www.jianshu.com/p/f3ef78deadaa 时间戳: https://tool.lu/timest ...

  9. 3ds max 学习笔记(四)--创建物体

    添加物体: 1.初创建物体,从单视图进行创建,便于处于同一平面,在透视图观看效果.2.在基本对象处选择“长方体”:左键开始制作,松开左键此时控制的是长方形的高,然后点击左键完成:注:在max里点击右键 ...

  10. JavaScript面向对象的三大特性

    1.JavaScript面向对象的三大特性 JavaScript的三大特性:封装性.继承性.多态性. 2.JavaScript实现封装特性 在一些静态类型的语言如java中,本身语法就提供了这些功能. ...