Erlang - If Else Condition



尝试计算分数并将其保持在0.2到1.5之间。下面的代码行得通吗?我不希望它回来,但要继续下去。

ok = if
Score > 1.5 ->
Score = 1.5;
true ->
ok
end,
ok =   if
Score < 0.2 ->
Score = 0.2;
true ->
ok
end,
put(score, Score),

下面的代码能工作吗?

否。在erlang中,一个变量只能赋值一次。这是你应该学会的第一件事。在此声明中:

if
Score > 1.5 -> ...

变量Score已经被分配了一个值,您将其与小数点后1.5进行比较。假设Score的值是2.0,那么特定if子句的主体执行:

Score = 1.5;

这相当于写:

2.0 = 1.5;

这将导致模式匹配错误:

  • 异常错误:右侧值1.5不匹配

在erlang中,一旦将值分配给变量,此后对该变量的任何后续分配都将被视为模式匹配,即等号右侧的值将与等号左侧的值进行模式匹配。


在erlang中,通常使用多个函数子句来模式匹配不同的值:

-module(my).
-compile(export_all).
compute(Score) when Score > 1.5 ->
1.5;
compute(Score) when Score < 0.2 ->
0.2;
compute(Score) ->
Score.

外壳内:

1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Score1 = my:compute(1.6).
1.5
3> Score2 = my:compute(1.5).
1.5
4> Score3 = my:compute(1.2).
1.2
5> Score4 = my:compute(0.1).
0.2
6> Score5 = my:compute(0.2). 
0.2

然后你可以在同一个模块中定义另一个函数,如下所示:

do_stuff(Score) ->
NewScore = compute(Score),
%Do something with NewScore here...

如果你想使用If语句,我会这样做:

-module(my).
-compile(export_all).
do_stuff(Score) ->
NewScore = if 
Score > 1.5   -> 1.5;
Score < 0.2   -> 0.2;
true          -> Score
end,
%Do something with NewScore here, for instance:
io:format("~w~n", [NewScore]).

为了使函数的长度不超过5-6行,将if语句移到另一个函数中会有所帮助。

另一种方法是使用erlang:min/2erlang:max/2来维持范围:

-module(my).
-compile(export_all).
do_stuff(Score) ->
max(min(Score, 1.5), 0.2).

如果Score大于1.5,则min/2将返回1.5,否则返回Score。然后,如果该结果小于0.2,则max/2将返回0.2,否则为min/2的结果。这是我们的测试功能:

test_do_stuff() ->
ScoresAndResults = [{0, 0.2},
{1.5, 1.5},
{0.2, 0.2},
{1.4999999, 1.4999999},
{1.5000001, 1.5},
{42, 1.5},
{0.19999999, 0.2},
{0.2000000000001, 0.2000000000001},
{1.2, 1.2},
{1, 1},
{-1, 0.2}],
{Scores, Results} = lists:unzip(ScoresAndResults),
Results = [do_stuff(Score) || Score <- Scores].

运行它会产生预期的结果:

1> my:test_do_stuff().
[0.2,1.5,0.2,1.4999999,1.5,1.5,0.2,0.2000000000001,1.2,1,0.2]

最新更新