【问题标题】:Erlang record handling using filter使用过滤器处理 Erlang 记录
【发布时间】:2013-02-26 03:40:15
【问题描述】:

我有以下代码从记录列表中返回一条记录,该记录的字段值等于 Accountnumber。

lookup(AccountNumber, [#account{no=AccountNumber} = Rec | _]) ->
    Rec;
lookup(AccountNumber, [_| T]) ->
    lookup(AccountNumber, T);
lookup(AccountNumber, []) ->
    not_found.

上面的代码工作正常,但是当我尝试使用以下代码将其转换为过滤器时:

lookup(AccountNumber, DBRef) ->
    lists:filter(fun(#account{no=AccountNumber} = Rec) -> Rec end, DBRef).

我收到以下错误:

** exception error: no case clause matching #account{no = 2,balance = 0,pin = undefined,name = "Ali",
                                                 transactions = []}
   in function  lists:'-filter/2-lc$^0/1-0-'/2 (lists.erl, line 1271)

错误的原因是什么?

【问题讨论】:

  • 尽管使用 map、fold 和 filter 等知名函数重写上述递归函数可能很诱人,但请记住 filter 会找到 all 匹配项元素,这意味着它总是搜索整个列表。 (这也意味着它可以返回多个命中,而不仅仅是第一个!)

标签: erlang record


【解决方案1】:

代码中存在多个问题

1.过滤器应该总是为所有列表元素返回原子真或假。这导致您出现错误。

2.当fun块外的变量用在fun头中时,它们不是模式匹配的,外面的变量被屏蔽了。因此模式匹配失败。

你可以在下面看到修改后的代码。

  lookup(AccountNumber, DBRef)  ->
    lists:filter(
      fun(#account{no=AccNo}) when AccNo =:= AccountNumber -> true;
         (_) -> false 
      end, DBRef).

【讨论】:

  • 为了表现得像上面的lookup 函数,您需要对filter 的结果进行大小写,看看它返回的是空列表(not_found)还是列表[Req] .现在它在成功时返回[Req],在失败时返回[]。您还需要考虑存在多个具有相同编号的帐户的可能性。
猜你喜欢
  • 2016-12-15
  • 2010-10-27
  • 1970-01-01
  • 2017-06-10
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 2013-04-06
相关资源
最近更新 更多