【问题标题】:Records in a guard警卫记录
【发布时间】:2011-01-30 22:05:48
【问题描述】:

我正在尝试使用此处描述的守卫中的记录[1]。如果我使用那里描述的简短形式:

handle(Msg, State) when Msg==#msg{to=void, no=3} ->

...我永远找不到匹配项...但是,如果我将其完全扩展为:

handle(Msg, State) when Msg#msg.to==void, Msg#msg.no==3 ->

...一切都很好。正如我对大多数 erlang 文档所做的那样,我读错了吗?

谢谢, --tim

[1] - http://www1.erlang.org/doc/reference_manual/records.html#id2278275

【问题讨论】:

  • 只是猜测,但您的第一个匹配假定记录中没有其他字段或所有其他字段都设置为未定义。如果 msg 记录有其他字段会导致它失败。
  • 谢谢 Jeremy,一定是这样(还有其他有价值的字段),我认为它们在语义上是等价的。再次感谢...
  • 进一步说明,您可以在函数签名中使用模式匹配来完成此操作。匹配失败,因为它进行了平等测试。您可能已经被 == 表示相等和 = 表示模式匹配中的绑定的视觉相似性绊倒了。

标签: erlang


【解决方案1】:

当记录很大时,匹配记录可能会很麻烦。我处理的方式是测试记录的第一个元素,应该是记录名:

当 element(1,Msg) == msg 时处理(Whatever)

【讨论】:

    【解决方案2】:

    您可能想改用以下模式,它简洁

    handle(#msg{to=void, no=3}=Msg, State) ->
        do_stuff(Msg).
    

    如果您不需要整个 msg 记录值,而只需要其中的某个字段,那么您可以像这样匹配和破坏

    handle(#msg{to=void, no=3, data=Data}, State) ->
        do_stuff(Data).
    

    【讨论】:

      【解决方案3】:

      当你在守卫中说#msg{to=void, no=3} 时,你没有提到的所有字段都将被设置为它们的默认值(通常是undefined)。因此,您的守卫未能匹配,因为未列出的某些字段不匹配。

      我倾向于在可能的情况下使用模式而不是守卫,所以我会将子句写成:

      handle(Msg = #msg{to=void, no=3}, State) ->
          ...
      

      此模式需要 Msg to msg record(一个 msg 记录大小的元组,第一个元素是 msg),to 元素必须是 voidno 元素必须是 3。 msg 记录的其他元素可以是任何东西。

      【讨论】:

      • 谢谢大家,大家都猜到了,我应该改用一个模式...这个学习曲线很陡峭但很有趣...再次感谢...
      【解决方案4】:

      我看到你已经解决了这个问题。请注意:在惯用的 Erlang 中,您通常会这样写匹配:

      handle(Msg = #msg{to = void, no = 3}, State) ->
      

      当然,这取决于品味,有时您会想要使用守卫来获得更令人愉悦的线对齐。

      【讨论】:

        猜你喜欢
        • 2017-05-08
        • 1970-01-01
        • 1970-01-01
        • 2011-06-19
        • 1970-01-01
        • 1970-01-01
        • 2016-04-13
        • 2011-04-09
        相关资源
        最近更新 更多