Erlang 模式记录

Erlang 模式记录,erlang,design-patterns,record,Erlang,Design Patterns,Record,我正在学习erlang,我在一些我不太理解的行为上绊倒了。以这段代码为例。(我知道我正在编程的东西有现有的库,但正如我所说的,我这样做是为了教育目的): 显然,它在模式中消化记录时遇到了一些问题,因为当我将代码更改为这种笨拙的变通方法时,它编译得很好: swapMaybe2 (Node, Tree) -> [Order, Parent, Root] = [Node#node.order, Node#node.parent, Tree#tree.root], case hig

我正在学习erlang,我在一些我不太理解的行为上绊倒了。以这段代码为例。(我知道我正在编程的东西有现有的库,但正如我所说的,我这样做是为了教育目的):

显然,它在模式中消化记录时遇到了一些问题,因为当我将代码更改为这种笨拙的变通方法时,它编译得很好:

swapMaybe2 (Node, Tree) ->
    [Order, Parent, Root] = [Node#node.order, Node#node.parent, Tree#tree.root],
    case highestOrderForWeight (Node#node.weight, Tree) of
        Order -> pass; 
        Parent -> pass;
        Root -> pass;
        Partner -> io:format ("Swapping ~p with ~p.~n", [Node#node.order, Partner] )
    end.
问题:

  • 如何访问模式中的记录字段
  • 如果不可能,原因为何
  • 如果无法做到这一点,通常的做法是什么

    • 确实不可能像您那样在
      案例中使用记录。模式匹配记录的工作原理如下:

       swapMayBe2(#node{order=Order, parent=Parent, root=Root} = Node, Tree) ->
           ...
      
      case Node of
          {node,_,_rec0,_,_,_} ->
              rec0;
          _ ->
              error({badrecord,node})
      end
      
      swapMaybe(#node{order=Order, parent=Parent}, Tree=#tree{root=Root}) ->
          case highestOrderForWeight (Weight, Tree) of
              Order -> pass; 
              Parent -> pass;
              Root -> pass;
              Partner -> io:format ("Swapping ~p with ~p.~n", [Order, Partner] )
          end.
      
      这将
      Order
      绑定到字段
      Order


      看看Erlang编程示例用户指南:

      实际上,记录只是编译时的语法糖,您可以使用
      'E'
      查看实际的构造。例如,
      Node#Node.order
      将替换为以下内容:

       swapMayBe2(#node{order=Order, parent=Parent, root=Root} = Node, Tree) ->
           ...
      
      case Node of
          {node,_,_rec0,_,_,_} ->
              rec0;
          _ ->
              error({badrecord,node})
      end
      
      swapMaybe(#node{order=Order, parent=Parent}, Tree=#tree{root=Root}) ->
          case highestOrderForWeight (Weight, Tree) of
              Order -> pass; 
              Parent -> pass;
              Root -> pass;
              Partner -> io:format ("Swapping ~p with ~p.~n", [Order, Partner] )
          end.
      
      当然,当您尝试使用
      Node#Node.order
      作为模式时,编译器会报告此构造的
      非法模式

      您的
      swapMaybe
      函数可以这样重写:

       swapMayBe2(#node{order=Order, parent=Parent, root=Root} = Node, Tree) ->
           ...
      
      case Node of
          {node,_,_rec0,_,_,_} ->
              rec0;
          _ ->
              error({badrecord,node})
      end
      
      swapMaybe(#node{order=Order, parent=Parent}, Tree=#tree{root=Root}) ->
          case highestOrderForWeight (Weight, Tree) of
              Order -> pass; 
              Parent -> pass;
              Root -> pass;
              Partner -> io:format ("Swapping ~p with ~p.~n", [Order, Partner] )
          end.
      

      模式不是计算结果与要匹配的对象匹配的任意表达式-例如,您不能编写:

        case ... of
            1 + 2 -> ...
      
      以及尝试与记录字段的值进行匹配:

        case some_integer(...) of
            Node#node.order -> ...
      
      其实是一回事。模式总是具有构造函数的形式——它描述事物的形状,而不是如何计算。如您所述,可以使用预实例化变量:

        Order = Node#node.order,
        case some_integer(...) of
            Order -> ...
      
      更常见的解决方案是将计算出的值放在保护中,如果您想要的表达式非常简单,因此允许在保护中使用:

      case some_integer(...) of
          Value when Value =:= Node#node.order -> ...
      
      如果表达式很短,您可能希望将它们组合在一个子句中,在保护中使用分号作为分隔符:

      case some_integer(...) of
          V when V =:= Node#node.order ; V =:= Node#node.parent ; V =:= Node#node.root ->
              ...;
          Other ->
              ...
      end
      

      (最后,作为风格问题,请不要在函数名和参数列表的左括号之间留空格。)

      谢谢。为什么第二个参数以
      树=
      开头,而第一个参数不以
      节点=
      开头?或者这是一种类型?@Hyperboreus这是可选的,它意味着您有一个代表整个树记录的变量
      ,同时分解它以获得
      变量。您也可以添加
      Node=
      ,但编译器会抱怨
      Node
      未使用。整个
      #tree{}
      记录将绑定到
      tree
      变量,但不需要
      Node
      变量。您还可以像这样对记录进行模式匹配:
      funcName(Tree=#Tree{})
      -在这种情况下,您只需对记录进行模式匹配,但不绑定任何记录变量。