我在erlang中编写一个函数,它应该能够以不同的顺序和不同的格式接受各种参数集,并且我使用非常严格的防护来确保正确的匹配。
我这样写一个长长的守卫并不罕见:
my_fun(List, Number, OptionalList, Record)
when is_list(List) andalso length(List) >= 5,
is_integer(Number) andalso Number >= 10 andalso Number =< 50 orelse Number =:= undefined,
is_list(OptionalList) orelse OptionalList =:= undefined,
is_record(Record, my_record) ->
我在这里使用的是orelse,而且它使得代码的可读性差得多,而且通常更长。
有没有办法使用和实现相同的保护逻辑;仅?
答案 0 :(得分:5)
不,您需要保留部分orelse
和andalso
,因为在使用,
和;
时,您实际上有许多替代方案(已分开)由;
)组成的几个条件(由,
分隔),以及至少一个备选方案中的每个条件必须为真。在这个例子中,你几乎有相反的情况:对于每个参数,你希望一个条件为真。
换句话说,像这样的警卫:
A, B; C, D
(几乎 1 )相当于:
(A andalso B) orelse (C andalso D)
并且如果不使用这些运算符,就无法执行(A orelse B) andalso (C orelse D)
之类的操作。
但是,您可以将此示例缩短一点:
is_list(List)
是多余的,因为如果length(List)
不是列表,List
将失败。在警卫中,“失败”并不意味着抛出错误;它只是意味着该条款不匹配。is_integer(Number)
几乎多余,因为您还有Number >= 10 andalso Number =< 50
。在Erlang中,可以比较任何两个术语的大小,因此如果Number
在此范围内,它肯定是一个数字。 (但它可能是浮点数而不是整数。)您可以匹配函数头中的记录,而不是is_record(Record, my_record)
:
my_fun(List, Number, OptionalList, Record = #my_record{})
1 如果A
或B
会引发异常,则orelse
版本将不匹配,而;
版本将匹配C, D
部分匹配。例如,此函数返回b
:
foo() when 1/0 == 1 orelse true ->
a;
foo() when 1/0 == 1; true ->
b.