变量作用域

子句中变量的生存期从它首次被绑定处开始,到子句中对该变量的最后一个引用处结束。变量的绑定只会在模式匹配中发生;可以将之认作是一个变量产生过程。后续对变量的所有引用都是对变量的值的使用表达式中的变量必须是经过绑定的。变量第一次出现时就被用在表达式中是非法的。比如:

  1. 1234
  1. f(X) -> Y = g(X), h(Y, X), p(Y).

第1行中,定义了变量X(它在进入函数时被绑定)。第2行中,使用了X,定义了Y(首次出现)。第3行中,使用了XY,然后在第4行中使用了Y

if、case和receive的作用域规则

ifcasereceive原语中引入的变量会被隐式导出到原语主体之外。比方我们有:

  1. f(X) ->
  2. case g(X) of
  3. true -> A = h(X);
  4. false -> A = k(X)
  5. end,
  6. ...

变量A在其被定义的case原语之后仍然有效。从ifcasereceive原语中导出变量时应注意一些规则:

ifcasereceive原语的不同分支中引入的变量集合必须相同,除非缺少的变量在原语外不再被引用。

例如以下代码:

  1. f(X) ->
  2. case g(X) of
  3. true -> A = h(X), B = A + 7;
  4. false -> B = 6
  5. end,
  6. h(A).

这段代码就是非法的。因为在对true分支求值时定义了变量AB,而在对false分支求值时只定义了B。在case原语之后,又在调用h(A)中引用了A——如果是fase分支被求值,则A尚未被定义。注意如果调用的不是h(A)而是h(B)则这段代码就是合法的,因为Bcase原语的两个分支中都有定义。

脚注

[1]附录A给出了Erlang的形式语法。
[2]许多人认为破坏性赋值会导致难以理解和易错的不清晰的程序。
[3]标记VarValue表示变量Var的值为Value
[4]假设所有函数调用都结束。
[5]即是说函数的与调用上下文无关。
[6]有时被称为垃圾箱。
[7]好吧,几乎是——想想看factorial(-1)
[8]如果不知道选哪个,选最漂亮的那个!
[*]译者注:list/1在较新版本的Erlang中已经不推荐使用,应使用is_list/1。感谢网友孔雀翎指出。