作用域
一、 Definition
名字(name)与实体(Entity)保持绑定关系的有效的那部分程序(代码范围)。 相应的区域就对应一个作用域区块。 同一个名称在程序的其他部分可能指向一个不同的实体或什么也不指向。从被引用的实体层面看(而非引用的名称),绑定的作用范围常称为实体的可见性(尤其在技术书籍中)
[引] 1960定义在ALGOL 60的规范
一个标识符可以表示一个对象、一个函数、一个标签或一个结构成员、联盟、或枚举、一个typedef名称、一个标签名称、一个宏名称;或一个宏观参数。相同的标识符在程序中的不同位置,可以表示不同的实体。[…]针对标识符指定的每一个不同的实体,该标识符仅在一个特定区域的程序文本中可见(即可使用),该区域便称为它的作用域。
根据绑定时机的不同,又分为词法作用域和动态作用域。[参考:Lexical-Scope VS Dynamic-Scope]
二、应用
作用域是名字解析(Name Resolution)的一部分。 应用特性如下:
- 不同的编程语言可能有不同的作用域和名字解析。
- 同一语言内也可能存在多种作用域,随实体的类型变化而不同。
- 作用域类别影响变量的绑定方式,根据语言使用静态作用域还是动态作用域变量的取值可能会有不同的结果。
- 针对作用域制定的规则称为作用域规则,和命名空间一样,作用域在模块化程序设计中是非常重要的,程序中一部分的改变不会影响到其他不相关的部分
语法规范
- 包含标识符的宣告或定义。
- 包含语句/表达式定义,或部分关于可运行的算法;
- 嵌套嵌套或被嵌套嵌套。
三、概述
当天我们谈论作用域的时候,通常会涉及到3个基本的概念:
- 作用域(scope)
- 生命周期(extent/lifetime)
- 上下文(context)
作用域(scope)和上下文(context)经常容易被搞混淆。作用域是标识符的一个属性,是固定的,而context是程序的一个属性,随着位置的改变而改变。
更确切的说,context是程序中位置的属性,要么是源代码(词法上下文)中的一个位置,要么是运行时(执行上下文、运行时上下文、或调用上下文)的一个点。执行上下文包含词法上下文(当前执行的点)和运行时状态,例如调用栈。因此,当正在执行的点在一个变量名称的作用范围中,变量(名称)在上下文中(意思是“在上下文中处于该点”),当执行点“退出变量(名称)的作用域”,例如从一个函数中返回,意味着“变量(名称)离开上下文”。狭义来讲,执行期间程序进入和退出变量作用域,便哦室执行时标志符是“在上下文中”或“不在上下文中”,因此标志符“进入上下文”或“离开上下文”就像程序进入或离开作用域。然而实际上更加松散。
作用域是源码层的概念,是标识符的属性,尤其是变量或函数名称 - 源码中的标志符指向程序中的实体 - 而且这个语言编译器或解析器行为的一部份,所以作用域的问题类似域指针(程序中常用的一种引用类型)。
决定标志符指向实体的技术被称为Name Resolution或Name Binding(尤其是在面向对象程序中),而且不同语言中技术也不同。给定一个标志符,程序(通常编译器或解析器)检测上下文中所用的实体来获取匹配的,为防止模糊(两个实体具有相同的名字,例如全局变量和本地变量具有相同的名字),Name Resolution 规则用于区分它们。据大部分情况下,Name Resolution遵守“inner-to-outer”规则。
当上下文中的两个标志符拥有相同的名字,指向不同的实体,那么通常说的“Name Masking”就出现了,此时更高优先级的名称(通常最近的)会“隐蔽”掉低优先级的名称。此场景中的变量被称为“Varialbe Shadowing”。
不同的编程语言就有不同的作用域规则,不同的声明类型和标志符。
作用域经常与语言的结构相关联,而且隐式确定,但许多语言还提供了构造专门用于控制作用域。
参考文章
3. DynamicBindingVsLexicalBinding
4. Lexical and dynamic binding refer to how variables are looked up by their names.