尝试计算分数并将其保持在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/2
和erlang: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]