4.5.2-1 全局作用域

简单地说,该部分的任务就是将语言的内置符号初始化,并注册到全局作用域中。初始化逻辑在$GCROOT/compile/internal/types2/universe.go中,通过init函数在编译器启动时自动初始化:

func init() {
	Universe = NewScope(nil, nopos, nopos, "universe") // 实例化全局作用域
	Unsafe = NewPackage("unsafe", "unsafe")
	Unsafe.complete = true

	defPredeclaredTypes()
	defPredeclaredConsts()
	defPredeclaredNil()
	defPredeclaredFuncs()
	defPredeclaredComparable()

	universeIota = Universe.Lookup("iota").(*Const)
	universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
	universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
	universeAny = Universe.Lookup("any").(*TypeName).typ.(*Interface)
	universeError = Universe.Lookup("error").(*TypeName).typ.(*Named)

	// "any" is only visible as constraint in a type parameter list
	delete(Universe.elems, "any")
}

该函数很清晰地表达了整个初始化过程,我们知道Scope中存放的是Object对象,所以各初始化函数的任务就是创建不同类型的Object对象并注册到全局变量Universe中。我们简单描述一下各个函数的任务:

  • defPredeclaredTypes 注册基本类型,例如 int8, float32, bool 等,包括前文提到的 Untyped 类型,该函数会为每种类型创建一个TypeName类型的 Object 对象。 值得注意的是该方法还初始化了 error 类型,初始化代码如下:

{
    res := NewVar(nopos, nil, "", Typ[String])                                // 方法返回类型为 string
    sig := &Signature{results: NewTuple(res)}                                 // 函数类型,只有返回 Tuple, 没有参数 Tuple
    err := NewFunc(nopos, nil, "Error", sig)                                  // 函数对象,函数名为 Error
    typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()} // 创建一个 defined type, 其 underlying type 是接口类型
    sig.recv = NewVar(nopos, nil, "", typ)                                    // 设置函数的 receiver, 使其成为上面接口的方法
    def(NewTypeName(nopos, nil, "error", typ))                                // 注册函数类型
}

上述代码相当于往 Universe 中注册了如下的接口类型:

type error interface {
    Error() string
}

而这正是 go 中对 error 类型的要求:实现Error() string方法,所以 error 类型的接口并没有在任何地方进行显示地申明,而是在此处通过代码创建的。

  • defPredeclaredConsts 注册语言内置的常量,一共有三个:true, false, iota. 为每个常量创建一个Const类型的 Object 对象。

  • defPredeclaredNil 注册nil, 其对应的是Nil类型的 Object 对象。

  • defPredeclaredFuncs 注册内置函数,例如 append, new, panic 等,每个内置函数对应一个Builtin类型的 Object 对象。

  • defPredeclaredComparable 与注册 error 类型相似,该方法注册了另一个隐式接口 comprable, 该接口是泛型的预定义 constraint. 例如可以如下方式使用该接口:

// 使用 comparable 来限定 T 的类型
func compare[T comparable](i, j T) bool {} 

最后更新于