Erlang:不变变量在案例表达式或参数列表中分配模式

Erlang : Invariable Variables assign pattern in Case Expression or Argument list

对于以下情况:

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.

问题:

  1. 第二种情况是否会占用额外的内存或其他资源?
  2. 推荐哪种方法?

@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() 它验证函数 returns 是一个 3 元素元组,其中第二个和第三个元素相等,并将第一个元素分配给 A。请注意,在这种情况下,使用 T 而不是 _T 不会引起警告,但对于 reader 来说更清楚的是,以后不会使用 _T

[编辑]

编译器做了很多优化,开发 beam 机器的团队负责节省时间和内存,所以你不应该首先考虑性能和优化。

编写应用程序时最重要的是将其拆分为具有正确职责的正确流程。

在我看来,坚持 OTP 原则也很重要:这将允许您使用许多有用的工具来调试、跟踪、调整...您的应用程序。其他人也更容易理解。

当然,就像在任何语言中一样,编写您的代码以使其最易被他人阅读。

如果您发现 2 种代码变体之间的差异很重要,我想这意味着您的应用程序确实遇到了麻烦,或者您正在尝试使用错误的工具来解决问题。

第二个版本是唯一合法的,也是一种很正常的表达方式。更正常的做法是完全避免 case 语句(如果可能的话)并在函数头中做这种事情,即使这意味着将这些行分解成一个小的辅助函数(这让你有机会有意义地 name 大小写匹配代表的过程并改进代码的语义)。

几乎从来没有像 {} 这样的 "nuple" 的情况。我想不出有什么理由会发生这种情况——非 Erlang 库可能有些奇怪,其中元组的语义目的无法识别。 (如果我得到它,我会认为它是坏数据并故意让它崩溃。)

至于性能...

变量在 Erlang 中尽可能晚地绑定,实际上 "binding" 是一个比您从其他非函数式动态类型语言中期望的更轻量级的操作(即使这个想法很灵活,因为有时什么都没有传递的不仅仅是一个参考)。唯一一次因为绑定而浪费循环的情况是当你分离出大量你永远不会使用的无意义的中间变量时——这就是为什么编译器对未使用的变量发出警告的原因。

在这种情况下,您没有得到无意义的中间体,但是:

foo(Data) ->
    {ok, Value} = somefun(Data),
    otherfun(Value).

{ok, Value}位经常被新手认为是"wasted"赋值,因为在长函数组合中不能直通。他们缺少的是,这是一个值 assertion,而不仅仅是一个赋值。许多函数要么有副作用,要么有可能搜索但找不到某些东西 return,例如断言友好的元组(例如,从外部资源读取、键值查找等)。这些非常重要,可以让您在开始使用不良数据做疯狂的事情之前尽早崩溃您的流程(这是对周期的真正浪费!)。

无论如何,这是错误担心性能的地方。 Erlang 中的元组匹配非常快,记录在编译时被简化为元组,因此它们完全等价。仅将参数传递给函数不需要传递或复制消息。

在你有一个工作系统来衡量之前,不要再考虑性能了。假设大规模并发系统的性能与尝试猜测一场风暴将产生多少特定规模的波浪一样有意义——只有在有机会进行测量时,您才能知道。 Erlang 中的一切都是可追溯的,因此 总是 明智的做法是将性能调整留到以后再做。 Erlang 对 post 开发跟踪、分析和调优非常友好,它使您的时间比处理器的时间重要得多。通过先编写一个漂亮的代码库来明智地利用你的时间,然后用你期望的任何负载测试它。我很少遇到我编写了惯用的 Erlang 代码(也就是说,没有在一个上帝进程中承担太多责任)并且最终遇到性能瓶颈的情况,这些瓶颈不是网络、磁盘访问或其他一些外部资源.