erlang语法
来源:互联网 发布:php sigusr2 编辑:程序博客网 时间:2024/06/05 02:46
1、退出,输入 haut().
2、-module
3、module_name:function_name( arguments )
例如调用tut:double(10),说明调用tut模块的double函数。
4、模块名为tut
-module(tut).-export( [double/1, fact/1] ).double(X)-> 2 * X.fact(1) -> 1; fact(N) -> N*fact(N-1).
分号表示函数还未结束。
点号表示函数已经结束。
变量必须以大写字母开头,小写开头的为字符串。
5、元组
可以返回多个值-module(tut).-export( [double/1] ).double(X) ->{X*2, X*3, X*4}.
6、列表赋值
10> [One,Two|Rest]=[1,2,3,4,5,6].[1,2,3,4,5,6]11> One. 112> Two.213> Rest.[3,4,5,6]14>
获取列表的长度
-module(tut).-export( [get_length/1] ).get_length([] ) ->0;get_length([First|Rest]) ->1+get_length(Rest).
字符串输出采用ASCII表示
>[97,98,99]."abc"
7、百分号表示注释
8、格式化输出
标准函数io:formatio:format("my name is ~w, my age is ~w~n", [biao, 20]).
9、/返回浮点数
div 整数除 rem 求余
10、'a' 等同于 a
11、元组嵌套赋值
1>F = {first, guo}.{first,guo}2> L = {last, biao}.{last,biao}3> Name = {person, F, L }.{person,{first,guo},{last,biao}}
12、元组元素提取,采用占位符(下划线)
6> Name.{person,{first,guo},{last,biao}}7> {_,{_,N1},{_,N2}} = Name.{person,{first,guo},{last,biao}}8> N1.guo9> N2.biao10>
13、获取列表的元素值 [H|T]
10> ThingstoBuy=[{apple, 5}, {pear,10}, {orange, 20} ].[{apple,5},{pear,10},{orange,20}]11> [Buy1|Others] = ThingstoBuy.[{apple,5},{pear,10},{orange,20}]12> Buy1.{apple,5}13> Others.[{pear,10},{orange,20}]
14、字符串=整数列表
Hello = "hello"整数列表中,所有的整数都是可打印字符时,才转为字符串。15> [1,2,3].[1,2,3]17> [97,98,99]."abc"
使用$来表示一个字符的ASCII值(Latin-1)
18> [$;s-32, $amp;i, $;r]."Sir"又例如23> [H|T]="cat"."cat"24> H.9925> T."at"
18、释放所有的变量绑定。f().
19、Erlang提供的命令。
pwd()打印当前路径,
切换当前目录到C盘根目录
1> cd("e:/erlang_src").<input type="button" e:/erlang_srcok
20、fun定义匿名函数,并可以赋给一个变量。类似函数指针。
4> Double = fun(X)->2*X end.AT#Fun<erl_eval.6.80247286>15> Double(2).4>
21、把fun作为参数传入
例如标准库中的lists:map(F,L).把F应用到列表的每个元素,并返回新列表。17> lists:map(Double, [1,2,3,4]).[2,4,6,8]
标准库lists:filter(P, L ).
把列表的每个元素作为P的参数,返回为TRUE的,才被放到结果列表中。小例子:查找奇数列表中的奇数。是否等于的测试符号:" =:= "25> Even = fun(X) -> X rem 2 /= 0 end.#Fun<erl_eval.6.80247286>26> Even(2).false27> lists:filter(Even,[1,2,3,4,5,6,7,8,9]).[1,3,5,7,9]
22、比较操作符
全等于 =:= 例如 1=:=1.0 false等于 == 例如 1==1.0 true不等于 /=
23、返回fun的函数。
28> Fruits=[apple,orange,pear].[apple,orange,pear]29> Test=fun(L)->( fun(X) -> lists:member(X,L) end) end.#Fun<erl_eval.6.80247286>31> Isfruits = Test( Fruits ).#Fun<erl_eval.6.80247286>32> Isfruits( apple ).true
23、for循环,Erlang中无循环控制,需要自定义的控制结构
-module(for).-export([for/3]).for(MAX,MAX,F) -> [F(MAX)];for(I,MAX,F) -> [F(I) | for(I+1,MAX,F)].39> c(for).{ok,for}40> for:for(1,10,fun(I)->I*2 end).[2,4,6,8,10,12,14,16,18,20]在模块中,如果使用-import(for, [for/3] ) 在使用for函数时,就不需要指定模块名。
24、列表解析
L=[1,2,3,4,5,6].[1,2,3,4,5,6]42> [2*X || X <- L].[2,4,6,8,10,12]43>例如[2*X || X <- L] 由F(X)组成的列表,其中X是L的每个元素。又例如49> L=[{orange, 8}, {apple, 5}, {pear, 10} ].[{orange,8},{apple,5},{pear,10}]50> [{Name, Number*2} || {Name,Number} <- L].[{orange,16},{apple,10},{pear,20}]注意{Name,Number}用于和L中的元素进行匹配。
25、过滤器
51> [X || {a, X} <- [{a,1}, {b,2}, {a,3}] ].[1,3]过滤出为a的值。过滤出奇数的另外一种实现。53> L = [1,2,3,4,5,6,7,8,9].[1,2,3,4,5,6,7,8,9]54> [X || X <- L, X rem 2 /= 0].[1,3,5,7,9]55>[X || QUALIFIER1,QUARLIFIER2...].QUALIFIER1...如果是 X <- L形式则为生成器。如果是布尔表达式则为过滤器。
26、快速排序算法
-module(qsort).-export([qsort/1]).qsort([]) -> [];qsort([Head|L] ) -> qsort([X || X <- L, X < Head]) ++ [Head] ++qsort([X || X <- L, X >= Head] ).
27、lists:seq(1,N) 返回1-N的整数列表。毕达哥拉斯三元组。
28、断言。可以用于简单的变量测试和比较。断言语句使用when关键字开头。
-module(maths).-export([max/2]).max(X, Y) when X > Y -> X;max(X, Y) -> Y.
29、断言谓词。
is_atom(X)is_integer(X)is_list(X)is_function(X,N)is_tuple(X) 是否元组is_record(X,Tag,N)
30、断言内建函数(BIF)
abs(X)element(N,X) 元组X的第N个元素hd(X) 列表X的头部tl(X) 列表X的尾部,除第一个元素以外的剩余元素。length(X) 列表的长度node() 当前节点 node(X) 创建节点round(X) 四舍五入为整数self() 当前进程的进程标示符size(X) 元组的大小例如:67> L=[1,2,3,4,5,6,7].[1,2,3,4,5,6,7]68> hd(L).169> tl(L).[2,3,4,5,6,7]
31、用分号分隔的断言表示 or
用逗号分隔的断言表示 andassert(X,Y) when is_integer(X), X>5, X>Y -> [X,Y]; % and 操作assert(X,Y) -> [Y,X].
32、andalso,orelse用于构建稍微复杂一些的断言。
33、记录的定义保存在.hrl文件中,这样可以被多个module共享,以保证是同一份定义。
在命令行中使用记录之前,先要读取记录hrl文件,命令为 rr("xxx.hrl").
34、record定义,表名字为todo,字段有status,who,memo
-record( todo, {status=ok, who = biao, memo=test}). -->保存在record.hrl中.插入三条记录76> X1=#todo{status=bad,who=zb,memo=test2}.\#todo{status = bad,who = zb,memo = test2}77> X2=#todo{}.#todo{status = ok,who = biao,memo = test}78> X3=X2#todo{who=biaobiao}. %复制一条记录,然后修改who的值#todo{status = ok,who = biaobiao,memo = test}rf(todo).去掉记录的定义,然后打印X2,会发现其实是元组。
35、提出RECORD记录值。
第一种方法。#todo{who=W, memo=M, status=S} = X3.
第二种方法。X3#todo.W X3#toto.M
36、case..of..end分支
例子:自定义filterfilter(P, [H|T]) -> case P(H) of true -> [H|filter(P, T)]; false->filter(P,T) end;filter(P,[]) -> [].13> IsBig = fun(X) -> X > 10 end.#Fun<erl_eval.6.80247286>14> maths:filter(IsBig, [1,3,4,11,20]).[11,20]
37、条件分支if..end
iftest(X) -> if X == 1 -> "return 1"; X == 2 -> "return 2"; true -> "return other" end.
38、try .of. catch.. after..end 为 case的增强版,带有异常捕捉功能。
三种类型的异常exit/throw/error异常捕捉例子:-module(try_test).-export([demo1/0,generate_exception/1,catcher/1]).generate_exception(1) -> a;generate_exception(2) -> throw(a);generate_exception(3) -> exit(a);generate_exception(4) -> {'EXIT', a};generate_exception(5) -> erlang:error(a).demo1() -> [catcher(I) || I <- [1,2,3,4,5]].catcher(N) -> try generate_exception(N) of Val -> { N, normal, Val} %%如果没有异常,这个generate_exception(N)的值就和VAL进行匹配。 catch throw:X -> {N, caught, throw, X }; exit:X -> {N, caught, exit, X }; error:X -> { N, caught, error, X } after io:format("test"). end.运行结果:6> try_test:demo1().[{1,normal,a}, {2,caught,throw,a}, {3,caught,exit,a}, {4,normal,{'EXIT',a}}, {5,caught,error,a}]
39、erlang:error提高错误信息的质量。
sqrt(X) when X < 0 -> erlang:error( { sqrtNagativeArgumentError, X } );sqrt(X) -> math:sqrt(X).运行后,有如下提示:7> maths:sqrt(-1).** exception error: {sqrtNagativeArgumentError,-1} in function maths:sqrt/1
40、函数返回值,
{ok, Val} 或者 {error, Why} 调用者模式匹配后进行处理。例如:
41、erlang中的小于等于:" =< ", 大于等于: ">="
例如:%%输出不同的结果getValue(X) when X >= 1, X =< 100 -> {ok, 'less than 100'};getValue(X) -> {error, 'larger than 100' }.%%调用getValue对结果输出deal(X) -> case getValue(X) of {ok, Info } -> io:format("ok print info: ~w~n", [Info]); {error, Info} -> io:format("error print info: ~w~n", [Info]) end.
42、捕获任何异常的写法 ( : )。
try expr of 模式匹配 -> ...catch _:- -> 异常处理end.
43、使用 erlang:get_stacktrace() 打印函数调用的栈信息。
demo2() ->try generate_exception(2)catch throw:X -> {X, erlang:get_stacktrace()}end.
44、BIF并非erlang编写,而是虚拟机上的基本操作,包含在erlang模块中,
并自动导入,所以使用时不需要用前缀,例如 erlang:tuple_to_list/1cat 和 'cat' 是一样的,为一个常量。元组转化为列表3> tuple_to_list({1, "cat", "hello"}).[1,"cat","hello"]获取当前时间4> time().{11,11,2}
45、二进制数据中的整数,必须是0-255.
超出255,会从0开始,例如256输出会变成0, 257变成1.erlang的函数注释:@spec func( arg1, arg2 ...) -> val
46、列表转成二进制数据。
@spec list_to_binary( L ) -> binary().11> list_to_binary([1,2,3]).<<1,2,3>>12> list_to_binary([<<1,2,3>>, 1,2,3,<<4,5,6>>]).<<1,2,3,1,2,3,4,5,6>>13>
47、列表分割
@spec split_binary(BIN, POS) -> {BIN1,BIN2}13> split_binary(<<1,2,3,4,5,6>>, 3).{<<1,2,3>>,<<4,5,6>>}
48、@spec term_to_binary(BIN) -> Term
把任何erlang值转成二进制,把格式也存入二进制中,用于文件传输和网络传输,可以还原的。17> term_to_binary({"cat", "abc"}).<<131,104,2,107,0,3,99,97,116,107,0,3,97,98,99>>18> binary_to_term(<<131,104,2,107,0,3,99,97,116,107,0,3,97,98,99>>).{"cat","abc"}
49、二进制的字节长度
@spec size(BIN) -> Int19> size(<<1,2,3,4,5,6>>).6
50、比特语法
例子,用16位存储RGB用16位存储,Red和Blue为5为,Green 6位20> Red = 10.1021> Green = 20.2022> Blue = 30.3023> Color = <<Red:5, Green:6, Blue:5>>.<<82,158>>采用模式匹配提出值24> <<R:5, G:6, B:5>> = Color.<<82,158>>25> R.1026> G.2027> B.3028>
51、比特语法表达式中的元素,有一项指明计算机系统的字节序。
big/little/native. 默认为big,运行时根据CPU来确定字节序则选native在不同机器之间进行整数、二进制之间的解包和封包,需要使用正确的字节序。例如<<123456:32/big, 45678:16/little>>
52、全局宏定义,使用问号获取。
-define(BUFFER, 2048).getDefine() -> ?BUFFER * 2.测试结果:38> maths:getDefine().4096
53、apply可以动态调用BIF,例如apply(erlang, atom_to_list, [hello]).
模块属性-import( lists, [map/2] ).引入lists:map/2, 在模块中调用就不需要指明前缀lists-export([getDefine/2]).只有导出函数,在模块外部才能被访问到。-compile(export_all).如果要把模块中的函数全部导出,可以使用-compile来代替-export.-vsn(1.0).表示模块的版本。
54、自定义的模块属性。
例如-author( biao ).使用maths:module_info().可以输出所有这些信息项。 50> maths:module_info(attributes). [{vsn,[1.0]}] 51> beam_lib:chunks("maths", [attributes]). %使用系统模块来获取。 {ok,{maths,[{attributes,[{vsn,[1.0]}]}]}}从以上结果抽取对应的值。beam_lib:chunks用来提取模块的属性,然后用以下函数可以提出属性值。 -module(extract).-export([extract/2]).extract(File, Key) -> case beam_lib:chunks(File, [attributes]) of {ok, {File,[{attributes,L}]}} -> case lookup( Key, L ) of {ok, Val} -> Val; error -> exit(notFound) end; _ -> exit( badFile ) end.lookup(Key, [{Key,Val}|_]) -> {ok,Val};lookup(Key, [_|T]) -> lookup(Key, T);lookup(Key, [] ) -> error.输出:53> extract:extract(maths, vsn).[1.0]
55、块表达式。
begin expr1, expr2 end. 返回的是最后一条expr的值。
56、布尔表达式
63> not true.false64> true and false.false65> true or false.true66> (2>1) or (3>4).trueerlang的预处理器是epp
57、转义符
\b 退格\d 删除\s 空格 \t tab \n 换行 \r回车 \^X 代表 CTRL+X ,X为A-Z或a-z\'单引号 \" 双引号 \\反斜杠 \C字母的ascii值。\NNN \NN \N 表示八进制数。
58、函数引用,使用fun funcname/argnum
-module(funRef).-export([double/1,double2/1]).square(X) -> X*X. double(L)->lists:map(fun square/1, L). %引用本地double2(L) -> lists:map( fun maths:sqrt/1, L ). %引用其他模块
59、包含文件,把文件引入当前模块,例如hrl文件
-include( File ).
-include_lib("kernel/include/file.hrl"). 包含lib下最新kernel下的file.hrl.
60、中缀操作符++ --
72> [1,2,3]++[4,5,6].[1,2,3,4,5,6]73> [1,2,3,3,3,4,5,3]--[3,3].[1,2,3,4,5,3]74> [1,2,3,4,3,3]--[3,3,3,3].[1,2,4]
61、宏定义
-define( BUFFER, 2048).-define( Test(A, B), {A,B,A,B}).预定义宏。print()-> io:format("~p,~p,~p~n", [?FILE,?MODULE,?LINE]).87> funRef:print()."./funRef.erl",funRef,7宏的流程控制,编译开关。-module(macro).-export([start/0,loop/1]).-ifdef(debug).-define(TRACE(X), io:format("Trace ~p~p:~p~n", [?MODULE,?LINE,X])).-else.-define(TRACE(X), void).-endif.start() -> loop(5).loop(0) -> void;loop(N) -> ?TRACE(N), loop(N-1).编译运行:107> c(macro,{d, debug}). %%引入debug定义{ok,macro}108> macro:start().Trace macro14:5Trace macro14:4Trace macro14:3Trace macro14:2Trace macro14:1void
62、在模式中使用匹配操作符。
test({name,Name}=Z|T) -> f(Z)...
63、K进制整数的表示方法。
15#11.15进制,其值为16.$a,$\^c,表示ascii值。
64、进程字典,由一系列的键值对组成。
3> get().[]4> put(x,20). %把x的值设置为20,并把原来的值返回。undefined5> put(x,30).206> get(x).307> put(y,40).undefined8> get(). %返回所有的进程字典[{y,40},{x,30}]9> erase(x). %删除字典x3010> get().[{y,40}]11> erase().[{y,40}]尽量少用进程字典,一般用于只读的一些参数设置。一次性写入的变量。
65、erlang:make_ref().创建一个唯一标签。
全局唯一。匹配时使用的。13> Data = make_ref().#Ref<0.0.0.64>14> Data.#Ref<0.0.0.64>
66、短路布尔表达式。andalso orelse 而 (and,or两个都要求值)。
比较表达式:X =< Y 小于等于X /= Y 不等于 仅适用于整数和浮点数的比较。X =:= Y 全等于 适用于所有的比较。和C++中的==一样。X =/= Y 不全等于 适用于所有的比较。和C++中的==一样。X == Y 等于 仅适用于整数和浮点数的比较。
67、下划线变量。
只使用一次的变量,例如open(File,_Mode) 等价于 open(File, _)退出shell 输入q().等同于init:stop().
68、加载路径:
code:add_patha(Dir).加到开头。 code:add_pathz(Dir).加到结尾。 code:all_loaded(). 已加载的路径。 code:get_path().查找路径设定值。 code:clash().检查加载错误。命令行增加加载路径:erl -pa Dir1 -pa Dir2 ....获取erlang所需的home目录 init:get_argument(home).
69、命令行脚本。
erl -noshell -s hello start -s init stop.用非交互式方式,调用hello:start(),然后调用init:stop().命令行中执行任意一个函数erl -eval 'io:format("test").' -noshell -s init stop.
70、一个相关的makefile
.SUFFIXES: .erl .beam.erl .beam: erlc -W $<ERL= erl -boot start_cleanMODS = module1 module2 module3all: compile ${ERL} -pa './dir' -s module1 start compile:${MODS:%=%.beam}clean: rm -rf *.beam erl_crash.dumperlang虚拟机的错误信息。webtool:start().可以看到地址。1> webtool:start().WebTool is available at http://localhost:8888/Or http://127.0.0.1:8888/{ok,<0.34.0>}
71、ERLANG中进程和操作系统是不同的,ERLANG中的进程是程序语言,并不属于操作系统。
每个进程都是独立运行的ERLANG虚拟机。Pid = spawn(Fun).产生一个新进程对Fun求值。Pid ! M 把消息M发送给Pid进程,返回M.Pid1 ! Pid2 ! Pid3 ! M..群发消息。receive ... Other .. end. 接受消息。
72、创建一个求面积的服务进程。
-module(area).-export([loop/0,rpc/2]).%%客户端rpc(Pid, Request) -> Pid ! {self(), Request }, receive {Pid, Response} -> io:format("get response: ~p~n", [Response]); _Other -> _Other end.%%服务端loop() -> receive {From, {rectangle, W, H}} -> From ! {self(), W * H}, loop(); {From, {circle, R} } -> From ! {self(), 3.14*R*R}, loop(); {From, _Other} -> From ! {self(),"i don't know~~"}, loop() end.运行情况:14> Pid = spawn(fun area:loop/0).<0.62.0>16> area:rpc(Pid, {rectangle, 4, 5}).get response: 20ok17> area:rpc(Pid, {circle, 3}).get response: 28.259999999999998ok注意:Pid ! M 本身是会返回消息M,所以在输出中也会体现。self()表示当前进程的进程号
73、erlang允许的最大进程数。
18> erlang:system_info(process_limit).32768要增加这个上限,再启动时使用+P参数C:\Documents and Settings\Administrator>erl +P 500002> erlang:system_info(process_limit).50000
74、计算创建进程消耗的CPU时间和实际时间。
-module(elapse).-compile(export_all).compute(N) -> Max = erlang:system_info( process_limit ), io:format("max process limit is: ~p~n", [Max] ), statistics(runtime), %%开始统计CPU消耗时间 statistics(wall_clock), %%开始统计实际消耗时间 L = for( 1, N, fun() -> spawn( fun() -> wait() end ) end ), %%启动N个进程。 io:format("in"), {_,Time1} = statistics( runtime ), %%统计时间 {_,Time2} = statistics( wall_clock ), %%统计时间 lists:foreach( fun( Pid ) -> Pid ! die end, L ), U1 = Time1 * 1000/N, U2 = Time2 * 1000/N, (pse ~p(um) CPU Time and ~p(um) Wall Time.", [U1, U2] ).wait() -> receive die -> void end.for( N, N, F ) -> [F()];for( I, N, F ) -> [F() | for(I+1,N,F)]. %%注意这里的for,不要写成F
75、receive 进程等待的超时时间设置。
-module(wait).-compile( export_all ).waiting( Time ) -> receive Time when Time > 100 -> 'time is larger than 100'; _ -> 'other time' after Time -> 'no request...' end.等待Time毫秒后,如果没有接收到合适的请求,则执行after后面的语句。after后面的箭头,极易遗漏!
76、只有超时的receive语句
例如让当前的进程停止T ms-module(sleep).-export([sleep/1]).sleep(T) -> receive after T -> void end.
77、永远等待 infinity
sleep()-> receive after infinity -> void end.
78、注册进程:发布一个进程标示符,以便其他进程与之通信。
register(AnAtom, Pid ).unregister(AnAtom).whereis(AnAtom) -> Pid | undefined 判断原子AnAtom是否已被注册。registered() -> [] 返回系统中所有已注册的名称列表。例如:6> Pid = spawn(fun area:loop/0).<0.42.0>7> register( area, Pid).可以看做是别名,进程退出时,自动取消注册。
79、spawn( Fun) 创建一个进程、执行Fun对应的函数。
-module(clock).-compile(export_all).start(Time, Fun) -> register( clock, spawn( fun() -> tick( Time, Fun) end ) ). %%创建一个进程,并给出别名,然后进程执行tick函数。stop() -> clock ! stop.tick( Time, Fun ) -> receive stop -> void after Time -> %% 不断地等待,超时后打印一条记录,又接着回调tick Fun(), tick(Time, Fun) end. 执行结果如下:27>clock:start(1000, fun()->io:format("test") end ).true28> test28> test28> test28> test28> test28> test28> test2828> test28> test28> test28>clock:stop().teststop
80、使用MFA创建进程。
spawn( Mod, Function, Args ).link(Pid) 把当前进程和Pid进程链接。unlink(Pid) 取消链接exit(Why) 退出,并广播这个Why原因内容。exit(Pid, Why) 向Pid发送退出信号。erlang:monitor(process, Pid) 建立一个监视器。监视器是单向的,而链接是双向。BIF函数:process_flag( trap_exit, true).把当前进程变成系统进程。系统进程可以捕获别的进程的退出状态。
81、
进程正常结束,发出normal信号,他的进程集合屏蔽这种信号。进程非正常结束,他的进程集中的非系统进程都会退出,系统进程才能处理这种信号。进程收到kill信号,不管是否是系统进程,全部退出,并且广播。
82、三种进程模式
Pid = spawn( fun() -> ... end ). 被创建的进程消亡,当前进程毫无察觉。 Pid = spawn_link( fun() -> ... end ).被创建的进程非正常消亡,当前进程也会退出。 被创建的进程退出,当前进程做错误处理。 process_flag(trap_exit, true), %先变成系统进程。 PID = spawn_link( fun() -> .. end ), loop(). loop( State) -> receive {'EXIT', Pid, Reason } -> ... loop( State1 ); ... end.
83、存活进程例子
-module(onexit).-compile( export_all).keep_alive( Name, Fun )-> %创建一个进程注册为Name,然后执行Fun函数。 register( Name, Pid = spawn( Fun) ), on_exit( Pid, fun(_Why) -> keep_alive(Name, Fun) end ).% 把当前进程和Pid链接,然后进程异常退出时,捕获并调用Fun函数处理。on_exit(Pid, Fun) -> process_flag( trap_exit, true), link( Pid ), receive { 'EXIT', Pid, Why } -> Fun(Why) end.
84、创建一个名字服务。
-module(kvs).-compile(export_all).%启动:创建一个服务进程,循环等待处理,并给予别名kvsstart() -> register(kvs, spawn( fun() -> loop() end )).%向服务端发起变更请求,并接收结果store(Key, Value) -> kvs ! {self(), {store, Key, Value}}, receive {kvs, Reply} -> Reply end.%向服务器发起查询请求,并接收结果lookup(Key) -> kvs ! {self(), {lookup, Key}}, receive {kvs, Reply} -> Reply end.%接收客户端请求,并把结果发给客户端loop()-> receive {From, {store, Key,Value} } -> put( Key, Value ), From ! {kvs, true}, loop(); {From, {lookup, Key} } -> From ! {kvs, get(Key) }, loop() end.运行结果:18> kvs:start().true19> kvs:store(money, 100).true20> kvs:store(name, biao).true21> kvs:lookup(name).biao22> kvs:lookup(money).100
85、启动节点时,给予名字。同一台机器。
erl -sname NameC:\Documents and Settings\Administrator>erl -sname biao1Eshell V5.8.4 (abort with ^G)(biao1@biao)1> cd ("e:/erlang_src").e:/erlang_srcok在第一个节点上运行服务(biao1@biao)2> kvs:start().true 在第二个节点上,远程发送消息来调用(biao2@biao)3> rpc:call(biao1@biao, kvs, store, [sex, male]).true(biao2@biao)4> rpc:call(biao1@biao, kvs, lookup, [name]).biao
86、在局域网内的不同机器之间。
erl -name biao1 -setcookie abc 运行在两个不同的网络上,需要用全名。需要DNS服务。两个节点之间需要使用相同的cookie。在/etc/hosts可以添加域名入口,内容格式为 网络IP地址 主机名或者域名 [主机名别名]。erl -sname biao1 表示短名,在同一台机器或者在局域网内,直接用短名即可。
87、判断节点(NODE)之间是否连通。
net_adm:ping(Node).设置erlang节点的cookieerlang:set_cookie(node(), abc).spawn( Node, Fun ) -> Pidspawn( Node, Mod, Func, Arg ) -> Pidspawn_link( Node, Fun ) -> Pidspawn_link( Node, Mod, Func, Arg) -> Pid.node()->Node. 返回本地节点的名字。nodes() ->Node[] 返回与当前节点连接的所有节点。monitor_node(Node, Flag ) 当前进程监视Node,如果Flag为true则打开,Flag为false则关闭。当前进程会收到信号{nodeup, Node}, {nodedown, Node }is_alive() -> bool() 本地节点状态是否正常。{RegName,Node} ! Msg 向节点Node的RegName进程发消息。
88、在因特网上两个节点通信
A、确保4396端口是通的,Erlang的epmd会使用这个端口。B、ERLANG端口使用。启动时erl -name .. -setcookie .. -kernel inet_dist_listen_min Min inet_dist_listen_max Max.C、节点之间必须拥有相同的cookie,具有相同cookie的相连接的节点群称为ERLANG集群。
89、apply(M,F,A),这个可以实现,模块函数的配置化。
rpc:call(Node, Mod, Function, Args) -> Result | {badrpc, Reason}erl -setcookie ABCEDEF
90、lib_chan模块,用来控制能够启动哪些进程。这个应该是第三方的包。
start_server()->true 启动一个服务。start_server( Conf) -> 按照配置启动一个服务。配置文件内容是一系列的元组,{port, NNN } 服务器的监听端口为NNN{service, S,password, P, mfa, SomeMod,SomeFunc,SomeArgs}定义由密码P保护的服务S,如果服务启动,则由SomeMod:SomeFunc(MM,ArgsC,SomeArgs}创建的进程会出处理来自客户端的消息。MM: 代理进程Pid,用于向客户端发消息ArgC:来自客户机的调用参数。 connect(Host, port, S, P, ArgC) -> {ok, Pid} | {error, Why}
91、Socket套接字
-module(socket_test).-compile(export_all).get_url() -> get_url( "www.google.com" ).get_url( Host ) -> %% 调用connect连接Host:80,产生一个套接字, %% 采用二级制传输,{packet, 0}意味着原封不动地返回TCP数据。 {ok, Socket} = gen_tcp:connect( Host, 80, [binary, {packet, 0}] ), %% 把消息发送到套接字 gen_tcp:send( Socket, "Get/HTTP/1.0\r\n\r\n"), %% 进程接收套接字返回的消息 receive_data( Socket, [] ).receive_data( Socket, Result ) -> receive %% 每次收到的Bin消息都放到列表的头部 {tcp, Socket, Bin } -> receive_data( Socket, [Bin|Result] ); %%接收完毕,把数据反转并转化为二级制数据 {tcp_closed, Socket } -> list_to_binary( lists:reverse(Result) ) end.运行情况:8> socket_test:get_url().<<"HTTP/1.0 405 Method Not Allowed\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 11815\r\nDate: Fri, 19 Aug 20"...>>9>
92、创建一个监听8888端口的服务
服务端-module(compute_server).-compile(export_all).start_server() -> %% 监听8888端口,并返回一个监听套接字Listen %% 字节流中的头部是4个字节 {ok,Listen} = gen_tcp:listen(8888, [binary, {packet, 4}, {reuseaddr, true}, {active, true}]), %%开始监听8888端口,等待连接 %%有新连接进来,产生一个新的连接套接字Socket {ok, Socket} = gen_tcp:accept(Listen), %%连接成功后,关掉监听器,新建的Socket不会受到影响。 gen_tcp:close( Listen ), loop( Socket ).loop( Socket ) -> receive {tcp, Socket, Bin } -> io:format("receive binary: ~p~n", [Bin]), Str = binary_to_term( Bin ), io:format("receive value: ~p~n", [Str]), Reply = Str, io:format("server reply: ~p~n", [Reply]), gen_tcp:send(Socket, term_to_binary(Reply) ), loop( Socket ); {tcp_closed, Socket } -> io:format("server socket closed.~n") end. 客户端:-module(compute_client).-compile(export_all).send( Str ) -> {ok, Socket} = gen_tcp:connect("localhost", 8888, [binary, {packet, 4}]), ok = gen_tcp:send(Socket, term_to_binary( Str) ), receive {tcp, Socket, Bin } -> io:format("client receive binary: ~p~n", [Bin] ), Val = binary_to_term( Bin ), io:format("client receive value: ~p~n", [Val] ), gen_tcp:close( Socket ) end.运行情况客户端2> compute_client:send("abc").client receive binary: <<131,107,0,3,97,98,99>>client receive value: "abc"ok服务端7> compute_server:start_server().receive binary: <<131,107,0,3,97,98,99>>receive value: "abc"server reply: "abc"server socket closed.ok
93、主动套接字
创建时设置{active, true}
数据到达时,系统向控制进程发送{ tcp, Socket, Data }
控制进程无法控制流量。
用于异步服务器,客户端不会被阻塞。
94、被动套接字
{actvie, false}gen_tcp:recv(Socket, N) 接收来自套接字的数据。N为接收的字节数,如果N=0,则接收所有的调用recv时,客户端会被阻塞。只能等待一个套接字的消息。
95、混合型Socket
{active, once } 主动接收一条消息,然后系统处于阻塞状态,必须调用inet:setopts(Socket, [{active, once}] )
96、inet:peername(Socket) ->{ok, {Ip, Port}} | {error, Why} 查看连接的来源。
97、ets 表类型
set 键不能相同。order set 排序的setbag 可以有相同的键,但不能有两个相同的元组。duplicate bag 可以有相同的键值,也可以有两个相同的元组。
98、set ordered_set,bag,duplicat_bag 操作
-module(ets_test).-export([start/0]).start() -> %%注意第一个参数为 fun test/1,即调用test函数 lists:foreach( fun test/1, [set, ordered_set, bag, duplicate_bag]).test( Mode ) -> %%创建一个tab表,返回表ID TabID = ets:new( tab, [Mode] ), ets:insert(TabID, {a, 1}), ets:insert(TabID, {b, 2}), ets:insert(TabID, {a, 1}), ets:insert(TabID, {a, 3}), ets:insert(TabID, {a, 2}), %% 把表数据转成列表。 List = ets:tab2list(TabID), %% 13位宽度显示。 io:format("~13w => ~p~n", [Mode, List]), %%删除表,释放空间 ets:delete( TabID ).运行:4> ets_test:start(). set => [{b,2},{a,2}] ordered_set => [{a,2},{b,2}] bag => [{b,2},{a,1},{a,3},{a,2}]duplicate_bag => [{b,2},{a,1},{a,1},{a,3},{a,2}]ok
99、@spec ets:new(Name, [Opt]) -> TabID
Name 一个原子Opt取值有 1) set | ordered_set | bag | duplicate_bag 2) private 私有表,只有所有者进程才能读写。 3) public 公开表 4) protected 只有所有者进程能写,其余知道表名字的进程可以读。 5) named_table 命名表,后续可以使用Name来操作这个表 6) {keypos,1} 设置键的位置。在record中使用。
ets:new的默认设置为
[set,protected, {keypos, 1}]
100、把服务器的公共部分、不怎么变化的部分放在一个文件中,
然后把变化的部分(业务逻辑)放在另外一个文件中, 通过回调实现解耦。服务端例子:-module(server1).-export([start/2,rpc/2]).%% 创建一个进程,并且进程注册名是Name,传入一个Mod模块名。start(Name, Mod ) -> register( Name, spawn( fun() -> loop(Name, Mod, Mod:init() ) end ) ).%% 进程Name, 循环接收消息,并调用Mod:handle(..,State)loop( Name, Mod, State ) -> receive { From, Request } -> {Response, State1} = Mod:handle(Request, State), From ! {Name, Response}, loop( Name, Mod, State1) end.%% 客户端向Name进程发送Request消息rpc( Name, Request ) -> Name ! {self(), Request}, receive {Name, Response} -> Response end. 被回调的Mod模块-module(name_server).-compile(export_all).-import(server1, [rpc/2]).%%被服务器回调的程序代码,可以把服务器代码当做一个模板init() -> dict:new(). handle( { add, Name, Place }, Dict ) -> {ok, dict:store( Name, Place,Dict) };handle( { whereis, Name }, Dict ) -> {dict:find(Name, Dict), Dict}.被回调的部分可以看做是接口。运行情况如下:10> server1:start(myserver, name_server).true11> server1:rpc(myserver, {add, biao, 'at home'}).ok12> server1:rpc(myserver, {whereis, biao}).{ok,'at home'}
101、支持事务的服务端程序
在handle处理异常时,给客户端发退出指令。-module(server2).-compile(export_all).%% 创建一个进程,并且进程注册名是Name,传入一个Mod模块名。start( Name, Mod ) -> register( Name, spawn( fun() -> loop(Name, Mod, Mod:init())end )).%% 进程Name, 循环接收消息,并调用Mod:handle(..,State)loop( Name, Mod, OldState ) -> receive {From, Request } -> try Mod:handle( Request, OldState ) of {Response, NewState} -> From ! {Name, ok, Response }, loop( Name, Mod, NewState ) catch _:Why -> io:format("Server ~p request ~p~n" "caused exception ~p~n", [Name, Request, Why] ), From ! {Name, crash }, loop( Name, Mod, OldState ) end end.%% 客户端向Name进程发送Request消息rpc( Name, Request ) -> Name ! {self(), Request}, receive {Name, crash} -> exit( rpc ); {Name, ok, Response} -> Response end.
102、一个空服务器,然后根据传入的指令进行操作。
服务端-module(server5).-compile(export_all).start() -> spawn( fun() -> wait() end ).wait() -> receive {become, F} -> F() end.rpc( Pid, Q) -> Pid ! { self(), Q }, receive {Pid, Reply} -> Reply end.具体的服务操作,把功能部分解耦出来。-module(fac_server5).-compile(export_all).loop() -> receive {From, {fac, N} } -> From ! {self(), fac(N)}, loop(); {become, Something} -> Something() end.fac(0) -> 1;fac(N) -> N * fac(N-1).运行情况:2> Pid = server5:start().<0.33.0>3> Pid ! {become, fun fac_server5:loop/0 }.{become,#Fun<fac_server5.loop.0>}4> server5:rpc(Pid, {fac, 3}).65> server5:rpc(Pid, {fac, 5}).120
103、服务器模板gen_server.
需要在开头使用 -behaviour( gen_server).回调函数有:init/1 初始化,返回一个状态,作为handle_call的输入handle_call/3 回调主体,模式匹配。handle_cast/2handle_info/2terminate/2code_change/3写个服务器程序,需要以下三步:1、确定回调模块的名称。这里为my_bank.2、接口说明start() 打开银行stop() 关闭银行new_account(Who) 开户 deposit(Who, Amount) 存钱withdraw(Who,Amount) 取钱3、编写回调函数init([]) -> {ok, State } %这里的State生成后,将传给后面的函数使用,是一个全局的对象handle_call(_Request, _From, State) -> {reply, Reply, State}handle_cast(_Msg, State) -> {noreply, State }handle_info(_Info, State) -> {noreply, State}terminate(_Reason, _State) -> okcode_change(_OldVsn, State, Extra ) -> {ok, State }例子:%%第一步,确定回调模块名称-module(my_bank).%-behaviour(gen_server).-compile(export_all).%%第二步,接口实现%% start_link启动一个本地的服务器{local,Name},第二个参数为回调模块。.%% 首先会调用MOD:init/1start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], [] ).%% gen_server:call(?MODULE,Term) 发起对Name服务器的远程调用。 stop() -> gen_server:call(?MODULE, stop ).new_account(Who) -> gen_server:call(?MODULE,{new,Who}).deposit(Who, Amount) -> gen_server:call(?MODULE, {add, Who, Amount}).withdraw(Who,Amount) -> gen_server:call(?MODULE,{remove, Who, Amount}).%%第三步 回调函数实现%%6个回调函数init([]) -> {ok, ets:new(?MODULE, [set]) }.%银行开户handle_call({new, Who}, _From, Tab) -> Reply = case ets:lookup(Tab, Who) of [] -> ets:insert(Tab, {Who, 0}), { welcome, Who }; [_] -> {Who, you_already_in_bank} end, {reply, Reply, Tab};%银行存钱handle_call({add, Who, X}, _From, Tab) -> Reply = case ets:lookup( Tab, Who ) of [] -> you_are_not_in_bank; [{Who, Balance}]-> NewBalance = Balance + X, ets:insert(Tab, {Who, NewBalance}), {thanks, Who, your_balance_now_is, NewBalance} end, {reply, Reply, Tab};%银行取钱handle_call( {remove, Who, X}, _From, Tab ) -> Reply = case ets:lookup( Tab, Who) of [] -> you_are_not_in_bank; [{Who, Balance}] when X =< Balance -> NewBalance = Balance - X, ets:insert(Tab, {Who, NewBalance} ), {thanks, Who, your_balance_now_is, NewBalance}; [{Who, _Balance}] -> {sorry, you_havnot_enough_money} end, {reply, Reply, Tab };%终止服务器程序的方法 handle_call(Stop, From, State) -> {stop,Reason,Reply,Tab}handle_call(stop, _From, Tab ) -> {stop, normal, stopped, Tab }.handle_cast(_Msg, State) -> {noreply, State }.handle_info(_Info, State) -> {noreply, State }.terminate(_Reason, _State) -> ok.code_change(_OldVsn, State, _Extra) -> {ok, State }.
104、gen_server:start_link(Name,Mod,InitArgs,Opts)
创建Name服务,调用Mod:init(InitArgs)启动服务。
105、gen_server:call(Name,Request).调用服务器程序,发起Request请求,会回调handle_call
106、gen_server:cast(Name,Name) 回调 hanle_cast(_Msg,State)
handle_cast(_Msg,State) -> {noreply, NewState}
107、handle_info() 用来处理服务器收到的原生消息,例如收到其他进程的{'EXIT',PID,WHAT}.
handle_info(_Info,State) -> {noreply,State}.
108、在handle_XXX()函数返回{stop, Reason, State}
或者直接终结服务器返回{'EXIT', reason},这些会回调terminate(Reason,NewState).
0 0
- erlang语法
- ErLang语法提要
- ErLang语法提要
- ErLang语法提要收藏
- Erlang基本语法
- Erlang基本语法一
- ErLang语法提要
- erlang比特语法
- ErLang语法提要
- Erlang学习: 比特语法
- erlang语法学习
- erlang 语法练习
- ERLANG 语法基础
- erlang语法提要
- erlang bit语法
- erlang的基本语法
- Erlang入门语法
- erlang的基本语法
- 普通开发者网络安全必读(阿里云舒著)
- 阿飞没撒附件为欧分角色额跟对方会更热
- 加核桃仁科技体育课他又复古文艺日生日H动画
- C++的坑真的多吗?
- Spring mvc + jackson2 返回json格式(包含日期格式解析)
- erlang语法
- 怎么说都是你有理
- webstorm快捷键大全
- Android SDK更新以及ADT更新出现问题的解决办法
- Week 5a - Mouse input and more lists ----mouse input
- 常用SVN 命令
- 蓝盘绿盘黑盘红盘的区别
- 平衡二叉树
- python编辑器对比和推荐