我刚刚开始摆弄Erlang。 我已经看过许多模式匹配用于函数声明的例子,如下所示:
factorCount (N) ->
Sqrt = math:sqrt (N),
ISqrt = trunc(Sqrt),
if ISqrt == Sqrt -> factorCount (N, ISqrt, 1, -1);
true -> factorCount (N, ISqrt, 1, 0)
end.
factorCount (_N, ISqrt, Candidate, Count) when Candidate > ISqrt -> Count;
factorCount ( N, ISqrt, Candidate, Count) ->
case N rem Candidate of
0 -> factorCount (N, ISqrt, Candidate + 1, Count + 2);
_ -> factorCount (N, ISqrt, Candidate + 1, Count)
end.
为什么这样做? 例如
factorCount (_N, ISqrt, Candidate, Count) when Candidate > ISqrt -> Count;
factorCount ( N, ISqrt, Candidate, Count) ->
为什么这不只是一个内部条件的函数呢?
答案 0 :(得分:4)
一个原因是可读性和可维护性。函数内部的条件往往会使代码由于额外的缩进而向右移动,并且与身体中的额外条件相结合会使更长的函数更难以阅读,推理和维护。
另一个原因是函数通常具有前置条件,并且守卫通常可以比嵌入函数体内的代码更清楚地表达这些前提条件。
还有一个原因是,在调用函数时总是会出现匹配参数的模式,因为这基本上是函数参数如何得到它们的绑定,所以在控件中使用这些绑定值是很自然的。防护是模式匹配的一种扩展,允许您检查单独模式匹配无法检查的内容。
答案 1 :(得分:3)
除了Steve's answer之外,如果我重写您的代码会更加明显:
factorCount(_N, ISqrt, Candidate, Count)
when Candidate > ISqrt ->
Count;
factorCount(N, ISqrt, Candidate, Count)
when N rem Candidate =:= 0 ->
factorCount(N, ISqrt, Candidate + 1, Count + 2);
factorCount(N, ISqrt, Candidate, Count) ->
factorCount(N, ISqrt, Candidate + 1, Count).
在代码中,您可以将模式匹配与某些警卫结合起来变得更加明显:
merge([{K, V1} | T1], [{K, V2} | T2]) ->
[{K, [V1, V2]} | merge(T1, T2)];
merge([{K1, V1} | T1], [{K2, _} | _] = L2)
when K1 < K2 ->
[{K1, [V1]} | merge(T1, L2)];
merge(L1, [{K2, V2} | T2]) ->
[{K2, [V2]} | merge(L1, T2)];
merge(L1, []) ->
[{K, [V]} || {K, V} <- L1].
如果我将第二个和第三个函数子句组合在一起只是为了在函数子句中进行K1 < K2
比较,这没有多大意义。