变量x的范围是程序的区域,其中x的使用指的是变量的声明。进行范围界定的基本原因之一是使程序不同部分中的变量彼此不同。由于仅有少量的简短变量名,并且程序员共享有关变量命名的习惯(例如,i用于数组索引),因此在任何大小适中的程序中,相同的变量名都将在多个不同的范围中使用。
范围界定通常分为两类:
1.静态作用域
2.动态范围
静态作用域:
静态作用域也称为词汇作用域。在这种范围内,变量始终指的是其顶层环境。这是程序文本的属性,与运行时调用堆栈无关。静态作用域还使编写模块化代码变得更加容易,因为程序员仅通过查看代码即可确定范围。相反,动态范围要求程序员预见所有可能的动态上下文。
在大多数编程语言(包括C,C++和Java,变量始终是静态(或词法)范围的,即,变量的绑定可以由程序文本确定,并且独立于运行时函数调用堆栈。
例如,以下程序的输出为10,即f()返回的值不依赖于谁在调用它(就像g()调用它并且具有值为20的斧头)。 f()始终返回全局变量x的值。
// A C program to demonstrate static scoping.
#include
int x = 10;
// Called by g()
int f()
{
return x;
}
// g() has its own variable
// named as x and calls f()
int g()
{
int x = 20;
return f();
}
int main()
{
printf("%d", g());
printf("\n");
return 0;
}
输出 :
10
总而言之,编译器首先在当前块中进行搜索,然后在全局变量中进行搜索,然后在依次较小的范围内进行搜索。
动态范围:
对于动态范围,全局标识符是指与最新环境关联的标识符,在现代语言中并不常见。用技术术语来说,这意味着每个标识符都具有绑定的全局堆栈,并且在最近的绑定中搜索标识符的出现。
简单来说,在动态范围界定中,编译器首先搜索当前块,然后依次搜索所有调用函数。
// Since dynamic scoping is very uncommon in
// the familiar languages, we consider the
// following pseudo code as our example. It
// prints 20 in a language that uses dynamic
// scoping.
int x = 10;
// Called by g()
int f()
{
return x;
}
// g() has its own variable
// named as x and calls f()
int g()
{
int x = 20;
return f();
}
main()
{
printf(g());
}
以使用动态范围界定的一种语言输出:
20
静态与动态范围
在大多数编程语言中,静态作用域是主要的。这仅仅是因为在静态作用域中,仅通过查看代码就可以很容易地推理和理解。通过查看编辑器中的文本,我们可以看到范围内的变量。
动态范围并不在乎代码的编写方式,而在乎代码的执行方式。每次执行新函数,都会将新作用域推入堆栈。
Perl支持动态和静态作用域。 Perl的关键字“ my”定义了一个静态范围内的局部变量,而关键字“ local”则定义了动态范围内的局部变量。
# A perl code to demonstrate dynamic scoping
$x = 10;
sub f
{
return $x;
}
sub g
{
# Since local is used, x uses
# dynamic scoping.
local $x = 20;
return f();
}
print g()."\n";
输出 :
20