我最近认真研究了Erlang编程,我有一个问题。 以下是Erlang的正确方法吗?这是(为了简洁而修改(没有退出消息),在基本验证后删除了日志)从ch4解决了环问题。进程在传递预期的消息次数后退出;第一个进程等待最后一条消息到达并退出。
除了对风格和内容的一般批评之外,你能不能告诉我,如果写这样一个特殊的1-2行函数是正确的风格,还是应该使用if-s,case-s等?
start_ring( 0, _, _ ) -> {error, badarg};
start_ring( _, 0, _ ) -> {error, badarg};
start_ring( M, N, Message ) ->
spawn( ring, run_ring, [M, N, Message, 0] ).
% last process that connects the ring
run_ring( M, 1, Message, Pid ) when is_pid(Pid) ->
loop_ring( M, Message, Pid, false );
% process in the middle
run_ring( M, N, Message, Pid ) when is_pid(Pid) ->
loop_ring( M, Message, spawn( ring, run_ring, [M, N-1, Message, Pid] ), false );
% first process - special case for one process
run_ring( M, 1, Message, _ ) ->
loop_ring( M, self() ! Message, self(), true );
% first process
run_ring( M, N, Message, _ ) ->
NextPid = spawn( ring, run_ring, [M, N-1, Message, self()] ),
loop_ring( M, NextPid ! Message, NextPid, true ).
loop_ring( 0, _, _, _ ) -> ok;
loop_ring( 1, Message, Next, true ) -> ok;
loop_ring( M, Message, Next, IsMaster ) ->
receive
Message -> loop_ring( M - 1, Next ! Message, Next, IsMaster )
end.
答案 0 :(得分:7)
我认为你的风格非常简洁!干得好!
一些评论(个人品味):
开始响铃可以改写为:
start_ring( M, N, Message ) when M < N, N > 0, M > 0 ->
spawn( ring, run_ring, [M, N, Message, 0] ).
如果使用不当,这将导致function_clause
错误。处理错误返回时有一个好习惯,即如果用户可以对错误做一些合理的事情,则返回例如{error, Reason}
,否则只是崩溃。我认为在这种情况下,崩溃是安全的,因为任何其他输入都是程序中的错误。
run_ring/4
+ loop_ring/4
:我不喜欢在具有多个子句的函数之间使用换行符。这使得更难以看到函数的开始和结束位置。然后可以将注释放在子句体内而不是外部。现在识别函数头更容易(并将函数看作一个单元):
run_ring(M, 1, Message, Pid) when is_pid(Pid) ->
% last process that connects the ring
loop_ring(M, Message, Pid, false);
run_ring(M, N, Message, Pid) when is_pid(Pid) ->
% process in the middle
loop_ring(M, Message, spawn(ring, run_ring, [M, N-1, Message, Pid]), false);
run_ring(M, 1, Message, _) ->
% first process - special case for one process
loop_ring(M, self() ! Message, self(), true);
run_ring(M, N, Message, _) ->
% first process
NextPid = spawn(ring, run_ring, [M, N-1, Message, self()]),
loop_ring(M, NextPid ! Message, NextPid, true).
我个人不喜欢括号内的空格(正如我所说,个人品味)。 :-)使代码更“蓬松”。
使用spawn_link/3
代替spawn/3
,除非您知道自己不需要它。在开发程序时,它可以更容易地检测错误等。
loop_ring/4
的第二个子句会发出编译器警告。请改用_Message
和_Next
(也可以将它们用于第一个条款,这是奖金文档!)
答案 1 :(得分:3)
根据Erlang best practices,应该避免if
和case
嵌套两次以上:
嵌套代码是包含的代码 case / if / receive语句 其他案例/ if / receive语句。它 编写风格很糟糕 深层嵌套代码 - 代码有一个 倾向于跨越页面 正确的,很快变得难以理解。 尝试将大部分代码限制为a 最多两个缩进级别。 这可以通过划分来实现 将代码转换为更短的函数。
除此之外,我想使用if/case
或简单的模式匹配是一种品味问题。就个人而言,我更喜欢使用模式匹配而不是if或case。所以,如果你问我,你会以正确的方式做到这一点。
关于if
和case
,通常可以将前者重写为后者。有人说:
“总是使用case,if构造 有点破碎“。
嗯,这两个结构的工作方式完全不同。在if
构造中评估的表达式是一个守护者并且它有很多限制 - 因为你不能对守卫产生副作用,而不考虑所采取的分支进行评估。案例构造没有这种“限制”。你可以在那里使用任何表达式,其结果将与形成案例的模式相匹配。
可能重复: