4.5.3-1.4 构建初始化顺序
全局变量与全局常量之间可能存在相互依赖的情况,如下列代码所示:
为了简化初始化时的执行逻辑,我们需要确定变量的初始化顺序,即按照其依赖关系的拓扑顺序进行初始化,同时也需要检测是否有循环依赖。该逻辑定义在文件$GCROOT/compile/internal/types2/initorder.go
中,入口方法是check.initOrder()
。该方法的效果就是初始化 info.InitOrder 字段。
在讨论Object对象时我们已经提到过,编译器特别定义了一个dependency对象来标识那些可用于初始化表达式的对象,所有的 Const, Var 以及 Func 对象都属于 dependency 对象。
对象的依赖关系保存在declInfo的deps
字段中,在对该对象进行类型检查时,检查器通过函数func (d *declInfo) addDep(obj Object) {}
将当前对象所依赖的对象保存起来。
计算初始化顺序的算法思路如下:先构建对象依赖关系的有向图(Directed Graph),再以每个节点的依赖数目为权重构建最小堆(Min Heap)并以此堆作为最小优先级队列(Priority Queue),因此队列头部的对象总是依赖其它对象最少的,所以该队列的遍历顺序就是初始化的顺序。
info.InitOrder 内只包含全局变量的初始化逻辑,常量的初始化在类型检查时已经完成,这里处理常量的依赖图只是为了检测循环依赖。
最后更新于