4.4.1 数据结构 - 作用域

作用域是编程语言的一个重要课题,go 语言采用的是静态作用域,即词法作用域。在编译器内部,根据作用域范围从大到小将其划分为:

  1. 全局作用域,该作用域内的对象在任何地方都可以访问,编译器中叫 Universe

  2. 包作用域

  3. 文件作用域,该作用域只在编译器内部使用,语言层面没有体现

  4. 块作用域,简单说即 {} 包围起来的代码片段,例如函数体、控制语句块(例如 if, for 等内部)

编译器采用树形结构来管理作用域,对应的数据结构定义在文件 $GCROOT/compile/internal/types2/scope.go 中:

type Scope struct {
    parent   *Scope            // 当前作用域的父作用域
    children []*Scope          // 当前作用域的子作用域
    elems    map[string]Object // 当前作用域所包含的符号对象,key 是符号名称
    pos, end syntax.Pos        // 作用域位置信息
    comment  string            // for debugging only
    isFunc   bool              // set if this is a function scope (internal use only)
}

Scope 定义了插入与查找符号的方法:

func (s *Scope) Lookup(name string) Object                                 { /* 忽略函数体 */ }
func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) { /* 忽略函数体 */ }
func (s *Scope) Insert(obj Object) Object                                  { /* 忽略函数体 */ }

Lookup 仅在本作用域内查找符号, LookupParent 则从当前作用域开始,顺着父作用域一直查找,这两个方法是进行符号解析的 API。 elems 用来存放当前作用域内名字到符号对象的映射,符号对象是实现了 Object 接口的结构,在后续会专门介绍。

最后更新于