lexical scoping翻译为词法作用域或静态作用域
dynamic scoping翻译为动态作用域
With lexical scope, a name always refers to its local lexical environment. This is a property of the program text and is made indenpendent of the runtime call stack by the language implementation. Because this matching only requires analysis of the static program text, this type of scoping is also called static scoping. Lexical scoping is standard in all ALGOL-based languages such as Pascal, Modula2 and Ada as well as in modern functional language such as ML and Haskell. It is also used in the C language and its syntactic and semantic relatives, although with different kinds of limitations. Static scoping allows the programmer to reason about object references such as parameters, variables, constants, types, functions, etc. as simple name substitutions. This makes it much easier to make modular code and reason about it, since the local naming structure can be understood in isolation. In contrast, dynamic scope forces the programmer to anticipate all possible dynamic contexts in whihc module's code my be invoked.
With dynamic scope, each identifier has a global stack of bindings. Introducing a local variable with name x pushes a binding onto the global x stack (which may have been empty), which is popped off when the control flow leaves the scope. Evaluating x in any context always yields the top binding. In other words, a global identifier refers to the identifier associated with the most recent envirenment. Note that this cannot be done at compile-time because the binding stack only exists at run-time, which is why this type of scoping is callled dynamic scoping.
它们是编程语言中变量可见性作用域的两种不同的方式。简单来说,词法作用域和你书写程序时变量定义的位置有关,而动态作用域和程序执行时的上下文有关。举例说明:
#!/bin/bash
x=1
function g()
{
echo $x
x=2
}
function f()
{
local x=3
g
}
f
echo $x
执行输出:
[yellia lua]$ ./scope.sh
3
1
由此可见bash采用的动态作用域。
下面再来看下lua的
#!/usr/local/bin/lua
x=1
local function g()
print(x)
x=2
end
local function f()
local x=3
g()
end
local function f2()
local x=3
local function g2()
print(x)
x=2
end
g2()
end
f()
print(x)
f2()
print(x)
执行的结果:
[yellia lua]$ ./scope.lua
1
2
3
2
由此可见lua采用的静态作用域,1,2的结果是因为g()函数的定义在f()定义之外,因此不能访问到x。当g()的函数定义到f()之内时,x可以被访问到。
静态作用域和first class(第一类值)的特性为实现闭包提供了支持。
再来看下expect呢,我们发现expect中的直接报错,为什么呢?原来expect中变量的实现很简单,根本没有全局变量和局部变量的概念,所有的变量只在当前命令的执行上下文中可见,这也就是为什么proc 定义的函数不能访问其之外定义变量的原因。
有兴趣的还可以看下javascript的实现,它也是支持闭包的语言。