【问题标题】:Removing orelse and andalso in long guards删除 orelse 和 andalso 在长警卫
【发布时间】:2016-09-28 10:00:05
【问题描述】:

我正在用 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 和 andalso 很多,它使代码的可读性大大降低,而且通常更长。

有没有办法使用 , 和 ; 来实现相同的保护逻辑只有?

【问题讨论】:

  • 考虑使用宏?以when ?is_integer_in_range(Number, 10, 50) 为例。

标签: erlang


【解决方案1】:

不,您需要保留一些orelseandalso,因为在使用,; 时,您基本上有许多替代方案(由; 分隔),其中包括几个条件(由, 分隔),并且至少一个备选方案中的每个 条件必须为真。在此示例中,您的情况几乎相反:对于每个参数,您希望 一个 条件为真。

换句话说,像这样的守卫:

A, B; C, D

(几乎1)等价于:

(A andalso B) orelse (C andalso D)

如果不使用这些运算符,就无法执行(A orelse B) andalso (C orelse D) 之类的操作。

不过,您可以将这个示例缩短一点:

  • is_list(List) 是多余的,因为如果 List 不是列表,length(List) 将失败。在守卫中,“失败”并不意味着抛出错误;它只是意味着该子句不匹配。
  • is_integer(Number)几乎是多余的,因为你也有Number &gt;= 10 andalso Number =&lt; 50。在 Erlang 中,可以比较任意两个词的大小,所以如果Number 在这个范围内,它肯定是一个数字。 (不过,它可以是浮点数而不是整数。)
  • 代替is_record(Record, my_record),您可以匹配函数头中的记录:

    my_fun(List, Number, OptionalList, Record = #my_record{})
    

1 如果AB 会引发异常,则orelse 版本将不匹配,而; 版本将在C, D 部分匹配时匹配。比如这个函数返回b

foo() when 1/0 == 1 orelse true ->
    a;
foo() when 1/0 == 1; true ->
    b.

【讨论】:

    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 2011-06-13
    • 2012-03-03
    • 2010-09-08
    • 2018-02-07
    • 2012-01-14
    • 2023-04-10
    相关资源
    最近更新 更多