Erlang中的if else语句等效于什么?

15

我有两个需要执行的代码部分。两者都是条件语句。

if Value1 < N do something 

else if Value1 >= N do something

if Value2 < N do something 

else if Value2 >= N do something

我希望每个语句都能执行一次。

在Erlang中,if语句怎么用?没有else。我使用多个守卫,但这看起来像是4个if语句。分成两组。

if some condition   
code;

if other condition  
code

end.

我遇到了语法错误。


我发现,如果你在Erlang中依赖于guards或case语句,大多数情况下你可能是“做错了”。作为替代方案,你应该大多数情况下使用模式匹配而不是guards和case语句。如果没有具体的例子,我们无法告诉你是否应该使用case、guard还是模式匹配,但与其他选择相比,模式匹配总是正确的。 - user177800
可能是重复的问题:如何实现if-else - Anderson Green
4个回答

23

一个 if 的形式是:

if
    <guard 1> -> <body1> ;
    <guard 2> -> <body2> ;
    ...
end

尝试在 if 子句中自上而下顺序使用 guards(它被定义为这样做),直到找到一个测试成功的条件,然后评估该子句的主体部分,并且 if 表达式会返回主体部分中最后一个表达式的值。所以,在其他语言中的 else 部分已经包含在其中了。如果没有任何 guard 成功,则会生成一个 if_clause 错误。常见的通用 guard 只是 true,该 guard 总是成功,但是 catch-all 可以是任何为真的内容。

case 的形式如下:

case <expr> of
    <pat 1> -> <body1> ;
    <pat 2> -> <body2> ;
    ...
end
它首先对表达式进行求值,然后尝试按照 case 从上到下的顺序匹配该值与模式匹配,直到找到一个匹配项,然后计算该条款的主体内容,并且 case 表达式返回主体中最后一个表达式的值。如果没有任何模式匹配,则会生成 case_clause 错误。
请注意,if 和 case 都是表达式(一切都是表达式),因此它们都必须返回值。这就是为什么如果没有成功/匹配任何内容就没有默认值的原因之一。此外,还要强制您覆盖所有选项;这对 case 尤为重要。if 只是 case 的退化情况,所以它继承了它。有关Erlang Rationale中 if 的历史问题,您可以在trapexit.org的用户贡献中找到。

我如何找到参考文献:“有一点历史,您可以在trapexit.org的用户贡献中找到Erlang Rationale。”? - user502187

13

Erlang不允许您没有true语句选项使用if。无论这是否是真实语句或实际的true由您决定,但通常情况下,您的true将是其他语言中的else

if 
    some_condition -> some_code;
    some_other_condition -> some_other_code;
    true -> else_code
end.

要了解更多相关内容,请查看 此页面上的 "What the If?" 部分。


4
这确实允许使用 if 语句而不需要 true 分支,并且在这种情况下会在运行时引发异常。 - Alexey Romanov
1
因此,“Erlang不允许在没有true语句选项的情况下使用if。”如果没有任何表达式被评估为true,则会引发异常。 - Reese Moore
6
但获得异常是好事。这意味着某个情况没有按照您计划的方式进行。可以说,捕获所有“else”子句与盲目捕获所有异常一样糟糕:如果 X > 0 -> ...; X < 0 -> ...; X =:= 0 -> ... end。比使用“true”作为最后一个子句更明确且更安全。 - I GIVE TERRIBLE ADVICE
没错,但是如果你想测试数学语法(而不是Haskell)中的 4<x<71<x<2-10<x<-7x>=20x<-100,并在每种情况下执行特定的操作,在其他情况下执行其他操作(一个假设的例子,也许)。当然,-100 <= x <= -10 or -7 <= x <= 1 or 2 <= x <= 4 or 7 <= x < 20 可能更明确,但是 true(或另一种语言中的 else)写起来更快,出错的可能性更小。 - Reese Moore
2
在撰写代码时,显式地书写它看起来可能会比较麻烦,但实际上它的错误率更低。如果你在代码中出现了错误,该错误只有在数据出现异常时才会浮出水面。尽管显式书写需要更多的时间,但总体而言更安全可靠,并且在以后阅读代码时易于理解。请参考您发布的链接,在底部附近,引用自理查德·奥基菲的话。 - I GIVE TERRIBLE ADVICE

6

请记住,Erlang中的if有一个返回值,它是一个表达式。这与C或Java中的if不同。

如果您想对某个值进行操作,则代码应该类似于以下内容;

if
  % do something and get the value
  X >= Val -> Something;
  % for doing something otherwise and get the value
  true -> Else_than_the_Something 
end.

请参见Erlang参考手册中关于if表达式的章节以获取更多细节。

5

首先,我建议您习惯使用“case”语句,因为“if”条件受到保护表达式的限制:

case custom_call(A) of
  1 -> do1(A);
  2 -> do2(A)
end.

除了'if'和'case'之外,还有一种可以从R13开始使用的条件执行方法:

  1> N =10.
  10
  2> ((N > 10) andalso more).      
  false
  3> ((N == 10) andalso equals).
  equals

如果我使用 case,它会在匹配某个 case 时退出吗?还是会执行该 case 并继续尝试匹配第二个? - some_id
没有理由盲目地使用 case ... of ... end 而不是 if。如果你的检查可以限制在 guards 上,就使用 'if'。否则,你会在 'case' 中使用无用的匹配子句来使你的代码变得复杂。 - I GIVE TERRIBLE ADVICE
好的,但我的问题仍然存在。如果执行一个if语句,代码会退出吗?还是它会执行语句并移动到下一个保护条件?我需要一些代码根据值来执行。然后我有另一个方法,应该根据另一个值做同样的事情。第一个if是Value >= queue:len,else应该是Value < queue:len。所以有两个if else语句。 - some_id
1
使用if或case语句,它将匹配第一个分支并执行,然后离开。只有当它不匹配第一个分支时,才会尝试第二个、第三个等等。这与C语言中的具有fall-through子句的“case”或“switch”不同。 - I GIVE TERRIBLE ADVICE
好的,谢谢。那么把第一个“if else”放在一个case里,然后把下一个“if else”放在第二个case里是可行的。我需要其中一个完成执行,然后继续执行下一部分并执行其中一个。 - some_id
试一下,你会发现它更短 ;) - I GIVE TERRIBLE ADVICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接