4.4.3 数据结构 - Object 对象
Object
定义了一个接口,用来表示程序中的各类命名实体,即前文一直提到的符号对象,例如函数、变量、类 型等。编译器内部为不同的符号类型定义了不同的数据结构,所有定义都在文件 $GCROOT/compile/internal/types2/object.go
中。接口
type Object interface{...}
的声明如下:// An Object describes a named language entity such as a package,
// constant, type, variable, function (incl. methods), or label.
// All objects implement the Object interface.
//
type Object interface {
Parent() *Scope // scope in which this object is declared; nil for methods and struct fields
Pos() syntax.Pos // position of object identifier in declaration
Pkg() *Package // package to which this object belongs; nil for labels and objects in the Universe scope
Name() string // package local object name
Type() Type // object type
Exported() bool // reports whether the name starts with a capital letter
Id() string // object name if exported, qualified name if not exported (see func Id)
// String returns a human-readable string of the object.
String() string
// order reflects a package-level object's source order: if object
// a is before object b in the source, then a.order() < b.order().
// order returns a value > 0 for package-level objects; it returns
// 0 for all other objects (including objects in file scopes).
order() uint32
// color returns the object's color.
color() color
// setType sets the type of the object.
setType(Type)
// setOrder sets the order number of the object. It must be > 0.
setOrder(uint32)
// setColor sets the object's color. It must not be white.
setColor(color color)
// setParent sets the parent scope of the object.
setParent(*Scope)
// sameId reports whether obj.Id() and Id(pkg, name) are the same.
sameId(pkg *Package, name string) bool
// scopePos returns the start position of the scope of this Object
scopePos() syntax.Pos
// setScopePos sets the start position of the scope for this Object.
setScopePos(pos syntax.Pos)
}
该接口申明的方法比较多,但基本都是属性的 Getter 或者 Setter 方法,公用信息定义在结构
type object struct{...}
中,具体声明如下:type object struct {
parent *Scope
pos syntax.Pos
pkg *Package
name string
typ Type
order_ uint32
color_ color
scopePos_ syntax.Pos
}
编译器一共定义了 8 类 Object, 包括:
- PagName: 包对象
- Const: 常量对象
- TypeName: 代表通过
type
关键字定义的类型,或者类型别名 - Var: 代表一个变量声明,通过用来表示函数的参数、返回值,以及结构体的 Field
- Func: 代表一个方法、函数声明,或者接口内的方法声明
- Label: 代表程序内的一个 label, 用于 break, goto 等关键字;其没有 type 属性
- Builtin: 代表一个内置函数
- Nil: 代表 nil 值
- dependency: 用来标识初始化表达式可能依赖的对象,只有
Const
,Var
, 以及Func
是合法的该类对象。该类对象用于构建全局变量的初始化顺序,这在后面会有详细介绍。
每种类型的自定义属性并不多,基本都只是复用了 object, 所以在这里就不一一列举代码了,详情请读者自行查阅
$GCROOT/compile/internal/types2/object.go
。每个 Object 对象都代表着程序的一个符号,所 以只有指向同一个符号的两个 Object 对象才是等价的,而在不同作用域的两个符号即使在结构上完全一样,也是不同的对象,这一点与类型的等价规则不同。类型的等价规则会在后面详细介绍。
Object 对象是类型检查的重要数据结构,准确地说,该对象的内部封装了符号对象的各方面信息:包、作用域、类型、位置信息等;每一个 Object 都与 AST 中的一个节点(Node)对应,类型检查器保存了这两类信息的映射关系(Checker 的 objMap 属性)。
类型检查的目的,就是将所有 Object 对象的类型属性,即 object 中的 typ 属性推导出来,并检查整个类型系统的兼容性。事实上,类型检查的整个逻辑都是围绕着 Object 对象展开的,我们会在类型检查逻辑一节对其进行详细分析。在此之前,我们先来熟悉一下编译器内部的类型数据结构。