Go语言实现递归时出现循环引用初始化报错该如何解决
错误原因
该cyclic definition初始化循环错误和递归逻辑本身无关,是Go全局变量初始化规则导致的:你当前直接在lookup全局变量的初始化表达式的闭包内部引用还未完成初始化的lookup变量,编译器判定为循环依赖。
修复方案
调整变量声明顺序,先声明lookup变量占位,再对其赋值,闭包内引用的就是已经完成声明的变量,不会触发初始化循环,修改后代码如下:
type AutoMapper func(field reflect.StructField, thing reflect.Value) map[string]interface{} // 先声明lookup变量,仅定义类型不赋值 var lookup func(payload interface{}) map[string]interface{} // 在init函数中完成lookup的初始化赋值 func init() { lookup = func() func(payload interface{}) map[string]interface{} { var handlePtr = func(field reflect.StructField, thing reflect.Value) map[string]interface{} { deref := reflect.Indirect(thing) if deref.CanAddr() { if deref.Kind() == reflect.Struct { return lookup(deref.Interface()) // 此时lookup已完成声明,运行时已完成赋值可正常调用 } return map[string]interface{}{ field.Tag.Get("hcl"): deref.Interface(), } } return map[string]interface{}{} } var checkForHcl = func(mapper AutoMapper) AutoMapper { return func(field reflect.StructField, thing reflect.Value) map[string]interface{} { if field.Tag.Get("hcl") != "" { return mapper(field, thing) } return map[string]interface{}{} } } lk := map[reflect.Kind]AutoMapper{} find := func(payload interface{}) map[string]interface{} { values := map[string]interface{}{} var t = reflect.TypeOf(payload) var v = reflect.ValueOf(payload) if t.Kind() == reflect.Ptr { t = t.Elem() v = v.Elem() } for i := 0; i < t.NumField(); i++ { field := t.Field(i) thing := v.Field(i) for key, value := range lk[thing.Kind()](field, thing) { values[key] = value } } return values } lk[reflect.Struct] = checkForHcl(func(f reflect.StructField, t reflect.Value) map[string]interface{} { return find(t.Interface()) }) lk[reflect.Slice] = checkForHcl(func(field reflect.StructField, thing reflect.Value) map[string]interface{} { return map[string]interface{}{ field.Tag.Get("hcl"): thing.Interface().([]string), } }) lk[reflect.Ptr] = checkForHcl(handlePtr) return find }() }
补充说明
Go全局变量初始化会按依赖顺序执行,如果你在变量的初始化表达式中直接引用该变量本身,编译器会判定为需要用变量本身的值来初始化自己,触发循环错误。先声明变量再赋值的写法,闭包捕获的是变量的引用,运行时调用递归逻辑时变量已经完成赋值,不会出现问题。
内容的提问来源于stack exchange,提问作者Christian Bongiorno
相关产品推荐
相关产品推荐

