对于以下情况:
case SomeTuple of
{} ->
doing1();
{A,B,C,D,E,F} ->
doing2_1(A),
doing2_2({A,B,C,D,E,F});
_ ->
doing3()
end.
我更喜欢写这样的东西:
case SomeTuple of
{} ->
doing1();
X = {A,_,_,_,_,_} ->
doing2_1(A),
doing2_2(X);
_ ->
doing3()
end.
问题:
答案 0 :(得分:0)
@haoxian,唯一的选择是第二种情况。 doing2_2({A,_,_,_,_,_})
被禁止,此代码将无法编译。在erlang中,变量 _
未分配,它只是告诉编译器它应该匹配任何erlang术语。 {A,_,_,_,_,_} = T
只是验证T
是6个元素的元组,并将其第一个元素分配给A
。
与使用语法_Var
不同。在这种情况下,_Var
是一个可以使用的真实变量(即使不推荐)。如果此变量稍后未在函数中使用,则此表示法指示编译器不发出警告。这种表示法通常用于函数,接收或案例条款,以提醒未使用术语的含义:
receive
{test, _From, Msg} -> io:format("receive test message ~p~n",[Msg]);
{read, From} -> From ! afunction()
end,
我也在一些模式匹配中看到了这种符号,例如{A,_T,_T} = function()
,它验证函数返回一个3元素元组,其中第二和第三元素相等,并将第一个元素分配给A
。请注意,在这种情况下,T
而不是_T
的使用不会引起警告,但读者会更清楚_T
以后不会使用。
<强> [编辑] 强>
编译器进行了大量优化,开发光束机的团队负责节省时间和内存,因此您不应该首先考虑性能和优化。
编写应用程序时最重要的是在正确的过程中将其拆分并具有正确的职责。
在我看来,遵守OTP原则也很重要:这将允许您使用许多有用的工具来调试,跟踪,调整......您的应用程序。其他人也更容易理解它。
当然,就像在任何语言中一样,编写代码使其成为其他人最可读的代码。
如果您遇到两个代码变体之间的差异很重要,我想这意味着您的应用程序遇到了麻烦,或者您正在尝试用错误的工具解决问题。
答案 1 :(得分:0)
第二个版本是唯一合法的版本,也是一种非常正常的表达方式。更正常的是完全避免case语句(如果可能的话)并在函数头中执行此类操作,即使这意味着将这些行分解为一个小辅助函数(这使您有机会有意义地 name 大小写匹配的过程代表并改进代码的语义。)
几乎从来没有一个像{}
这样的“nuple”。我无法想到任何理由,为什么会出现这种情况 - 非Erlang库可能存在一些奇怪现象,其中元组的语义目的无法识别。 (如果我得到了,我会认为它是错误的数据并让它故意崩溃。)
至于表现......
变量在Erlang中尽可能晚地绑定,实际上“绑定”是一个比你可能期望的其他动态类型语言更加轻量级的操作(即使这个想法很灵活,因为它有时只不过是一个参考传递)。你唯一一次结束浪费周期进行绑定的时候就是你分出大量无意义的中间变量而你永远不会使用 - 这就是编译器发出关于未使用变量的警告的原因。
在这种情况下,你 无法获得无意义的中间体,但是:
foo(Data) ->
{ok, Value} = somefun(Data),
otherfun(Value).
{ok, Value}
位通常被新手视为“浪费”的赋值,因为它不能在长函数组合中直接传递。他们缺少的是这是一个值断言,而不仅仅是一个赋值。许多具有副作用或有可能搜索而不能找到某些东西的函数返回这样一个断言友好的元组(例如从外部资源读取,键值查找等)。这些非常重要,让您在开始使用不良数据做出疯狂的事情之前尽早崩溃您的过程(这真的是浪费周期!)。
在任何情况下,这都是错误的让人担心性能的地方。 Erlang中的元组匹配非常快,并且在编译时将记录简化为元组,因此它们完全相同。仅仅将参数传递给函数不需要传递或复制消息。
在您有一个可测量的工作系统之前,请忘掉性能。假设大规模并发系统中的性能与试图猜测风暴将产生多少一定大小的波浪一样有意义 - 在你有机会测量之前,你根本就不会知道。 Erlang中的Everthing是可追踪的,所以总是智能,以便稍后进行性能调整。 Erlang对开发后的跟踪,分析和调优非常友好,它使您的时间远比处理器更重要。首先编写一个漂亮的代码库,然后用你期望的任何负载测试它,明智地利用你的时间。我很少有一些案例,我写过惯用的Erlang代码(也就是说,在一个上帝程序中没有承担太多责任),实际上还遇到了不是网络,磁盘访问或其他外部资源的性能瓶颈