- 浏览: 982262 次
- 性别:
- 来自: 广州
最新评论
-
qingchuwudi:
有用,非常感谢!
erlang进程的优先级 -
zfjdiamond:
你好 这条命令 在那里输入??
你们有yum 我有LuaRocks -
simsunny22:
这个是在linux下运行的吧,在window下怎么运行escr ...
escript的高级特性 -
mozhenghua:
http://www.erlang.org/doc/apps/ ...
mnesia 分布协调的几个细节 -
fxltsbl:
A new record of 108000 HTTP req ...
Haproxy 1.4-dev2: barrier of 100k HTTP req/s crossed
Parameterized modules in Erlang
请参考这篇文章 http://ftp.sunet.se/pub/lang/erlang/workshop/2003/paper/p29-carlsson.pdf
我这里讲述的重点是如何实现的。先看代码:
root@nd-desktop:~/test/m# cat main.erl
% File: main.erl
-module(main).
-export([start/0]).
start() ->
M1 = print:new("Humpty"),
M2 = print:new("Dumpty"),
M1:message("Hello!"),
M2:message("Hi!"),
ok.
root@nd-desktop:~/test/m# cat print.erl
% File: print.erl
-module(print, [Name]).
-export([message/1]).
message(Text) ->
io:fwrite("~s: '~s'~n", [Name, Text]),
ok.
编译运行
root@nd-desktop:~/test/m# erlc *.erl
root@nd-desktop:~/test/m# erl -noshell -s main -s erlang halt
Humpty: 'Hello!'
Dumpty: 'Hi!'
在使用上是模拟面向对象的, 面向对象的同学会感到很亲切。但是erlang如何做到这个魔术的呢?
我们来分析下:
root@nd-desktop:~/test/m# erlc +"'S'" *.erl
root@nd-desktop:~/test/m# cat main.S
{module, main}. %% version = 0
{exports, [{module_info,0},{module_info,1},{start,0}]}.
{attributes, []}.
{labels, 7}.
{function, start, 0, 2}.
{label,1}.
{func_info,{atom,main},{atom,start},0}.
{label,2}.
{allocate_zero,1,0}.
{move,{literal,"Humpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{y,0}}.
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{trim,1,0}.
{move,{literal,"Hi!"},{x,0}}.
{apply,1}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 4}.
{label,3}.
{func_info,{atom,main},{atom,module_info},0}.
{label,4}.
{move,{atom,main},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 6}.
{label,5}.
{func_info,{atom,main},{atom,module_info},1}.
{label,6}.
{move,{x,0},{x,1}}.
{move,{atom,main},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
root@nd-desktop:~/test/m# cat print.S
{module, print}. %% version = 0
{exports, [{instance,1},{message,2},{module_info,0},{module_info,1},{new,1}]}.
{attributes, [{abstract,[true]}]}.
{labels, 11}.
{function, new, 1, 2}.
{label,1}.
{func_info,{atom,print},{atom,new},1}.
{label,2}.
{call_only,1,{f,4}}.
{function, instance, 1, 4}.
{label,3}.
{func_info,{atom,print},{atom,instance},1}.
{label,4}.
{test_heap,3,1}.
{put_tuple,2,{x,1}}.
{put,{atom,print}}.
{put,{x,0}}.
{move,{x,1},{x,0}}.
return.
{function, message, 2, 6}.
{label,5}.
{func_info,{atom,print},{atom,message},2}.
{label,6}.
{test,is_tuple,{f,5},[{x,1}]}.
{test,test_arity,{f,5},[{x,1},2]}.
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}.
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
{move,{literal,"~s: '~s'~n"},{x,0}}.
{call_ext,2,{extfunc,io,fwrite,2}}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 8}.
{label,7}.
{func_info,{atom,print},{atom,module_info},0}.
{label,8}.
{move,{atom,print},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 10}.
{label,9}.
{func_info,{atom,print},{atom,module_info},1}.
{label,10}.
{move,{x,0},{x,1}}.
{move,{atom,print},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
先看
print.S
这个模块导出的函数除了module_info外还有3个导出 new/1, instance/1, 更重要的是 message在源码里面是/1, 但是导出是/2,很奇怪是吗?
我们再看下 new 和 instance 返回一个tuple{print, Arg}.
message函数呢?
{test,is_tuple,{f,5},[{x,1}]}. %% 判断第二个参数是否是tuple
{test,test_arity,{f,5},[{x,1},2]}. %%tuple的个数是不是2
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}. %%取出tuple的第二个参数, 这个就是源码里面的Name模块参数
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
我演示下:
root@nd-desktop:~/test/m# erl
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
1> m(print).
Module print compiled: Date: September 25 2009, Time: 07.23
Compiler options: [{cwd,"/root/test/m"},{outdir,"/root/test/m"}]
Object file: /root/test/m/print.beam
Exports:
instance/1
message/2
module_info/0
module_info/1
new/1
ok
2> print:new(tag1).
{print,tag1}
3> print:instance(tag2).
{print,tag2}
4> print:message("hello", print:new(tag1)).
tag1: 'hello'
ok
main.S 就是这么调用我们的print模块的。
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
压入的参数正是 (Message, print:new(tag)), 然后是apply opcode.
我们看下apply opcode:
OpCase(i_apply): {
Eterm* next;
SWAPOUT;
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
r(0) = reg[0];
SET_CP(c_p, I+1);
SET_I(next);
Dispatch();
}
I = handle_error(c_p, I, reg, apply_3);
goto post_error_handling;
}
static Uint*
apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
{
int arity;
Export* ep;
Eterm tmp, this;
/*
* Check the arguments which should be of the form apply(Module,
* Function, Arguments) where Function is an atom and
* Arguments is an arity long list of terms.
*/
if (is_not_atom(function)) {
/*
* No need to test args here -- done below.
*/
error:
p->freason = BADARG;
error2:
reg[0] = module;
reg[1] = function;
reg[2] = args;
return 0;
}
/* The module argument may be either an atom or an abstract module
* (currently implemented using tuples, but this might change).
*/
this = THE_NON_VALUE;
if (is_not_atom(module)) {
Eterm* tp;
if (is_not_tuple(module)) goto error;
tp = tuple_val(module);
if (arityval(tp[0]) < 1) goto error;
this = module;
module = tp[1];
if (is_not_atom(module)) goto error;
}
/*
* Walk down the 3rd parameter of apply (the argument list) and copy
* the parameters to the x registers (reg[]). If the module argument
* was an abstract module, add 1 to the function arity and put the
* module argument in the n+1st x register as a THIS reference.
*/
tmp = args;
arity = 0;
while (is_list(tmp)) {
if (arity < (MAX_REG - 1)) {
reg[arity++] = CAR(list_val(tmp));
tmp = CDR(list_val(tmp));
} else {
p->freason = SYSTEM_LIMIT;
goto error2;
}
}
if (is_not_nil(tmp)) { /* Must be well-formed list */
goto error;
}
if (this != THE_NON_VALUE) {
reg[arity++] = this;
}
...
}
上面的代码就是干我们上面解释的事情的。
结论: 模块参数化完全是个语法糖, 没有任何magic。所以这个特性在hipe下也可以放心大胆用。
请参考这篇文章 http://ftp.sunet.se/pub/lang/erlang/workshop/2003/paper/p29-carlsson.pdf
我这里讲述的重点是如何实现的。先看代码:
root@nd-desktop:~/test/m# cat main.erl
% File: main.erl
-module(main).
-export([start/0]).
start() ->
M1 = print:new("Humpty"),
M2 = print:new("Dumpty"),
M1:message("Hello!"),
M2:message("Hi!"),
ok.
root@nd-desktop:~/test/m# cat print.erl
% File: print.erl
-module(print, [Name]).
-export([message/1]).
message(Text) ->
io:fwrite("~s: '~s'~n", [Name, Text]),
ok.
编译运行
root@nd-desktop:~/test/m# erlc *.erl
root@nd-desktop:~/test/m# erl -noshell -s main -s erlang halt
Humpty: 'Hello!'
Dumpty: 'Hi!'
在使用上是模拟面向对象的, 面向对象的同学会感到很亲切。但是erlang如何做到这个魔术的呢?
我们来分析下:
root@nd-desktop:~/test/m# erlc +"'S'" *.erl
root@nd-desktop:~/test/m# cat main.S
{module, main}. %% version = 0
{exports, [{module_info,0},{module_info,1},{start,0}]}.
{attributes, []}.
{labels, 7}.
{function, start, 0, 2}.
{label,1}.
{func_info,{atom,main},{atom,start},0}.
{label,2}.
{allocate_zero,1,0}.
{move,{literal,"Humpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{y,0}}.
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{trim,1,0}.
{move,{literal,"Hi!"},{x,0}}.
{apply,1}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 4}.
{label,3}.
{func_info,{atom,main},{atom,module_info},0}.
{label,4}.
{move,{atom,main},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 6}.
{label,5}.
{func_info,{atom,main},{atom,module_info},1}.
{label,6}.
{move,{x,0},{x,1}}.
{move,{atom,main},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
root@nd-desktop:~/test/m# cat print.S
{module, print}. %% version = 0
{exports, [{instance,1},{message,2},{module_info,0},{module_info,1},{new,1}]}.
{attributes, [{abstract,[true]}]}.
{labels, 11}.
{function, new, 1, 2}.
{label,1}.
{func_info,{atom,print},{atom,new},1}.
{label,2}.
{call_only,1,{f,4}}.
{function, instance, 1, 4}.
{label,3}.
{func_info,{atom,print},{atom,instance},1}.
{label,4}.
{test_heap,3,1}.
{put_tuple,2,{x,1}}.
{put,{atom,print}}.
{put,{x,0}}.
{move,{x,1},{x,0}}.
return.
{function, message, 2, 6}.
{label,5}.
{func_info,{atom,print},{atom,message},2}.
{label,6}.
{test,is_tuple,{f,5},[{x,1}]}.
{test,test_arity,{f,5},[{x,1},2]}.
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}.
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
{move,{literal,"~s: '~s'~n"},{x,0}}.
{call_ext,2,{extfunc,io,fwrite,2}}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 8}.
{label,7}.
{func_info,{atom,print},{atom,module_info},0}.
{label,8}.
{move,{atom,print},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 10}.
{label,9}.
{func_info,{atom,print},{atom,module_info},1}.
{label,10}.
{move,{x,0},{x,1}}.
{move,{atom,print},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
先看
print.S
这个模块导出的函数除了module_info外还有3个导出 new/1, instance/1, 更重要的是 message在源码里面是/1, 但是导出是/2,很奇怪是吗?
我们再看下 new 和 instance 返回一个tuple{print, Arg}.
message函数呢?
{test,is_tuple,{f,5},[{x,1}]}. %% 判断第二个参数是否是tuple
{test,test_arity,{f,5},[{x,1},2]}. %%tuple的个数是不是2
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}. %%取出tuple的第二个参数, 这个就是源码里面的Name模块参数
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
我演示下:
root@nd-desktop:~/test/m# erl
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
1> m(print).
Module print compiled: Date: September 25 2009, Time: 07.23
Compiler options: [{cwd,"/root/test/m"},{outdir,"/root/test/m"}]
Object file: /root/test/m/print.beam
Exports:
instance/1
message/2
module_info/0
module_info/1
new/1
ok
2> print:new(tag1).
{print,tag1}
3> print:instance(tag2).
{print,tag2}
4> print:message("hello", print:new(tag1)).
tag1: 'hello'
ok
main.S 就是这么调用我们的print模块的。
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
压入的参数正是 (Message, print:new(tag)), 然后是apply opcode.
我们看下apply opcode:
OpCase(i_apply): {
Eterm* next;
SWAPOUT;
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
r(0) = reg[0];
SET_CP(c_p, I+1);
SET_I(next);
Dispatch();
}
I = handle_error(c_p, I, reg, apply_3);
goto post_error_handling;
}
static Uint*
apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
{
int arity;
Export* ep;
Eterm tmp, this;
/*
* Check the arguments which should be of the form apply(Module,
* Function, Arguments) where Function is an atom and
* Arguments is an arity long list of terms.
*/
if (is_not_atom(function)) {
/*
* No need to test args here -- done below.
*/
error:
p->freason = BADARG;
error2:
reg[0] = module;
reg[1] = function;
reg[2] = args;
return 0;
}
/* The module argument may be either an atom or an abstract module
* (currently implemented using tuples, but this might change).
*/
this = THE_NON_VALUE;
if (is_not_atom(module)) {
Eterm* tp;
if (is_not_tuple(module)) goto error;
tp = tuple_val(module);
if (arityval(tp[0]) < 1) goto error;
this = module;
module = tp[1];
if (is_not_atom(module)) goto error;
}
/*
* Walk down the 3rd parameter of apply (the argument list) and copy
* the parameters to the x registers (reg[]). If the module argument
* was an abstract module, add 1 to the function arity and put the
* module argument in the n+1st x register as a THIS reference.
*/
tmp = args;
arity = 0;
while (is_list(tmp)) {
if (arity < (MAX_REG - 1)) {
reg[arity++] = CAR(list_val(tmp));
tmp = CDR(list_val(tmp));
} else {
p->freason = SYSTEM_LIMIT;
goto error2;
}
}
if (is_not_nil(tmp)) { /* Must be well-formed list */
goto error;
}
if (this != THE_NON_VALUE) {
reg[arity++] = this;
}
...
}
上面的代码就是干我们上面解释的事情的。
结论: 模块参数化完全是个语法糖, 没有任何magic。所以这个特性在hipe下也可以放心大胆用。
评论
2 楼
z416177937
2010-08-18
在这儿我知道了,这种方法如何应用,而且是可以应用的。后面具体的解释以后看,貌似有点麻烦。先知其然吧。
1 楼
argan
2009-09-25
哈哈,不错,本来只知其然,现在知道一点所以然了
发表评论
-
OTP R14A今天发布了
2010-06-17 14:36 2677以下是这次发布的亮点,没有太大的性能改进, 主要是修理了很多B ... -
R14A实现了EEP31,添加了binary模块
2010-05-21 15:15 3030Erlang的binary数据结构非常强大,而且偏向底层,在作 ... -
如何查看节点的可用句柄数目和已用句柄数
2010-04-08 03:31 4814很多同学在使用erlang的过程中, 碰到了很奇怪的问题, 后 ... -
获取Erlang系统信息的代码片段
2010-04-06 21:49 3475从lib/megaco/src/tcp/megaco_tcp_ ... -
iolist跟list有什么区别?
2010-04-06 20:30 6529看到erlang-china.org上有个 ... -
erlang:send_after和erlang:start_timer的使用解释
2010-04-06 18:31 8386前段时间arksea 同学提出这个问题, 因为文档里面写的很不 ... -
Latest news from the Erlang/OTP team at Ericsson 2010
2010-04-05 19:23 2013参考Talk http://www.erlang-factor ... -
对try 异常 运行的疑问,为什么出现两种结果
2010-04-05 19:22 2842郎咸武<langxianzhe@163.com> ... -
Erlang ERTS Async基础设施
2010-03-19 00:03 2517其实Erts的Async做的很不错的, 相当的完备, 性能又高 ... -
CloudI 0.0.9 Released, A Cloud as an Interface
2010-03-09 22:32 2476基于Erlang的云平台 看了下代码 质量还是不错的 完成了不 ... -
Memory matters - even in Erlang (再次说明了了解内存如何工作的必要性)
2010-03-09 20:26 3439原文地址:http://www.lshift.net/blog ... -
Some simple examples of using Erlang’s XPath implementation
2010-03-08 23:30 2050原文地址 http://www.lshift.net/blog ... -
lcnt 环境搭建
2010-02-26 16:19 2614抄书:otp_doc_html_R13B04/lib/tool ... -
Erlang强大的代码重构工具 tidier
2010-02-25 16:22 2486Jan 29, 2010 We are very happy ... -
[Feb 24 2010] Erlang/OTP R13B04 has been released
2010-02-25 00:31 1387Erlang/OTP R13B04 has been rele ... -
R13B04 Installation
2010-01-28 10:28 1390R13B04后erlang的源码编译为了考虑移植性,就改变了编 ... -
Running tests
2010-01-19 14:51 1486R13B03以后 OTP的模块加入了大量的测试模块,这些模块都 ... -
R13B04在细化Binary heap
2010-01-14 15:11 1508从github otp的更新日志可以清楚的看到otp R13B ... -
R13B03 binary vheap有助减少binary内存压力
2009-11-29 16:07 1668R13B03 binary vheap有助减少binary内存 ... -
erl_nif 扩展erlang的另外一种方法
2009-11-26 01:02 3218我们知道扩展erl有2种方法, driver和port. 这2 ...
相关推荐
Erlang OTP设计原则强调模块化的代码组织,因此通常建议将接口函数(如`start_link/1`和`button/1`)与回调函数放在同一个模块中,以便于理解和维护。在`code_lock`模块中,`init/1`函数初始化状态机,`locked/2`和`...
为了定义一个Supervisor,我们需要创建一个新的Erlang模块,并声明它遵循`supervisor`行为。具体来说: 1. **模块定义**: ```erlang -module(ch_sup). -behaviour(supervisor). -export([start_link/0]). -...
创建一个基本的supervisor,我们需要定义一个行为模块,实现`behaviour()`声明为`supervisor`,并提供`init/1`回调来初始化进程树。`init/1`回调返回一个tuple,其中包含启动策略和进程定义列表。 ```erlang -...
创建一个简单的Erlang模块`tut.erl`,包含基本的打印功能。通过编译和运行该模块来检查Erlang是否正确安装和配置。 以上是对Erlang及其核心特性的详细介绍,希望对您了解和学习Erlang有所帮助。
这些语言通过不同的机制实现模块化,如条件预处理、包导入、类定义等,共同推动了模块化编程的发展。 #### 前端代码演变与Kissy模块化实践 前端开发经历了从混沌至现代的演化历程: - **混沌时期**:早期网页混杂...
Erlang 支持模式匹配,因此一个函数可以有多个实现,根据传入参数的不同而自动选择合适的实现。 ##### 3.3 原子(Atoms) - **原子** 是 Erlang 中的常量类型之一,类似于其他语言中的字符串常量,但性能更高。...
字符串化宏参数是指将宏参数转换为字符串的过程。手册中详细介绍了字符串化宏参数的方法及应用场景。 ### 1.8 记录 **1.8.1 定义记录** 记录是一种具有命名字段的数据结构,用于表示具有固定字段集的对象。手册中...
通过以上步骤,开发者可以有效地组织和管理Erlang项目,实现模块化开发,并利用rebar进行自动化构建和测试,提高开发效率。在实际的Web开发中,如nigrogen2框架,rebar同样能帮助开发者轻松管理项目依赖,快速构建...
2. **src**:源代码文件通常放在这里,以.erl为扩展名,例如`module.erl`代表一个名为`module`的Erlang模块。 3. **include**:这个目录用于放置头文件,通常包含常量定义和类型声明,以.hrl为扩展名。 4. **test*...
EWSD交换机基于模块化设计,包含硬件和软件两大部分。硬件部分包括中央处理器单元(CPU)、存储单元、接口模块、电源模块等。软件部分则由操作系统、应用程序和服务程序组成,这些程序协同工作,实现呼叫处理、路由...
结构化编程强调的是将程序分解成若干个较小的功能模块,每个模块负责完成特定的任务。这种方法有利于提高代码的可读性和可维护性。面向过程编程是一种基于结构化编程思想的方法论,通过定义不同的函数来实现不同的...
函数式编程作为一种强大的编程范式,不仅提供了更为简洁优雅的代码结构,还促进了软件开发的模块化和可复用性。尽管存在一定的学习门槛,但对于希望提高代码质量和维护性的开发者来说,掌握函数式编程的基本原理是...
- 通过设置队列参数来实现消息的优先级排序。 **38. RabbitMQ是否支持多租户(Multi-tenancy)?** - 通过虚拟主机(VHosts)实现多租户功能,隔离不同用户的资源。 #### 六、安全性 **39. RabbitMQ如何实现安全...
- **消息处理器**:包括生产者(Producer)和消费者(Consumer)接口及其实现,它们负责将消息发送到消息队列或将队列中的消息消费掉。 - **消息模型**:定义了业务消息的数据结构,可能包括实体类和序列化/反序列化...