Erlang Case语句

4

我有以下Erlang代码,当我尝试编译它时,会出现以下警告,但这是有道理的。该函数需要两个参数,但我需要匹配“其他所有东西”,而不是x、y或z。

-module(crop).
-export([fall_velocity/2]).

fall_velocity(P, D) when D >= 0 ->
case P of
x -> math:sqrt(2 * 9.8 * D);
y -> math:sqrt(2 * 1.6 * D);
z -> math:sqrt(2 * 3.71 * D);
(_)-> io:format("no match:~p~n")
end.

crop.erl:9: Warning: wrong number of arguments in format call. 

我尝试在io:format之后使用匿名变量,但仍然不行。
2个回答

9
在你使用的格式中,~p表示打印数值。因此,你必须指定要打印的数值。
在case语句的最后一行必须是:
_ -> io:format("no match ~p~n",[P])

此外,io:format返回'ok'。因此,如果P不是x、y或z,您的函数将返回'ok'而不是数值。我建议返回标记值以分离正确和错误的返回。类似于:
fall_velocity(P, D) when D >= 0 ->
case P of
x -> {ok,math:sqrt(2 * 9.8 * D)};
y -> {ok,math:sqrt(2 * 1.6 * D)};
z -> {ok,math:sqrt(2 * 3.71 * D)};
Otherwise-> io:format("no match:~p~n",[Otherwise]),
            {error, "coordinate is not x y or z"}
end.

1
我会抛出一个异常,或者干脆不检查除了x、y、z以外的任何东西。Erlang失败得很明显,没有必要过度处理。 - Berzemus
如果不进行检查,你可能会在调用函数之后很长时间才发现错误。{ok,R} = fall_velocity(A,B) 可以更早地指出错误。 - Odobenus Rosmarus
1
实际上,这取决于谁调用函数。如果该函数是API的一部分,则标记值确实受欢迎。但是,如果该函数是您代码库深处的内部部分,您最终会在各个地方使用case语句,不断检查自己的代码,这是一个不必要的麻烦。让它失败就好了。 - Berzemus
这是一件很容易检查的事情,所以"他们"决定为此添加一个警告检查。这只是一个警告,如果您决定忽略它,那么在运行代码时将会出现错误。 - rvirding

3
为了更明确地回应其他答案的评论,这是我写该函数的方式:
-module(crop).
-export([fall_velocity/2]).

fall_velocity(P, D) when D >= 0 ->
    case P of
        x -> math:sqrt(2 * 9.8 * D);
        y -> math:sqrt(2 * 1.6 * D);
        z -> math:sqrt(2 * 3.71 * D)
    end.

也就是说,在你的case表达式中不要处理不正确的参数。如果有人将foo作为参数传递,你将会得到错误{case_clause, foo},以及指向这个函数和它的调用方的堆栈跟踪。这也意味着,由于使用不正确的参数调用此函数不能将不正确的值泄漏到其余代码中。
像其他答案中所述,返回{ok, Result} | {error, Error}同样有效。您需要选择最适合您情况的变体。

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