作为对“我的变量在哪里”的非常基本解释,考虑一下这个示例模块中的倒计时功能:
-module(example).
-export([countdown/1]).
-spec countdown(non_neg_integer()) -> ok.
countdown(0) ->
io:format("Blastoff!~n");
countdown(N) when N > 0 ->
ok = io:format("Counting down in: ~w~n", [N]),
Next = N - 1,
countdown(Next).
如果我们达到基本情况,即0,那么我们就会停止。整个函数的返回值是原子ok(因为这是成功调用io:format/2的返回值)。
如果输入大于0,那么我们匹配第二个子句,这意味着我们为这个特定的迭代指定N 唯一的输入参数。我们要做的下一件事是进行输出调用。然后我们将Next 赋值给N - 1。然后我们使用当前调用主体中Next 的值作为输入参数再次调用相同的函数(循环)。
下一次迭代所有变量都是全新的,因为这是一个全新的执行上下文。旧的N 和Next 不再存在。事实上,它们并不存在于堆栈中的任何地方,因为 Erlang 使用“tail call optimization”来维护constant space 中的递归尾调用,就像大多数其他语言会执行显式的for 或while 或@ 987654340@ 或 [插入表格]。
正如 Alexy 所指出的,请注意标记 fun——它是 Erlang 中的关键字,而不是合法的函数名称。它是anonymous function(也称为lambda)的非名称。换句话说,除非您提供标签,否则每个匿名函数的名称都只是fun。
fun 也是用于按标签引用函数(用作值本身)而不是调用它的关键字。例如,countdown(10) 使用参数10 调用上述函数。 引用函数作为fun countdown/1 将函数本身作为值返回。也就是说,顺便说一下,为什么模块顶部的函数导出声明写成-module([countdown/1]),因为那是这个函数的显式名称。考虑一下:
1> c(example).
{ok,example}
2> example:countdown(2).
Counting down in: 2
Counting down in: 1
Blastoff!
ok
3> Countdown = fun example:countdown/1.
#Fun<example.countdown.1>
4> Countdown(2).
Counting down in: 2
Counting down in: 1
Blastoff!
ok
当我谈到这个主题时......
与大多数语言相比,Erlang 的关键字很少(实际上语法也很少)。这里是the list of reserved words:
andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse receive rem try when xor