Erlang 模式记录
我正在学习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
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{})
-在这种情况下,您只需对记录进行模式匹配,但不绑定任何记录变量。