为了账号安全,请及时绑定邮箱和手机立即绑定

我如何在golang中进行这种递归

我如何在golang中进行这种递归

Go
芜湖不芜 2022-10-10 18:54:58
我有下面的代码,我正在尝试进行递归。但是,go 编译器抱怨循环引用。当然我有一个循环引用;这是一个递归。我尝试将递归移入主函数并移出。同样的问题。我怎样才能实现这种递归?错误行是:return lookup(deref.Interface()) // recursion error 'cyclic definition'christianb@christianb-mac terraform-provider% go build# github.com/terraform-provider/pkg/foo/repositories.go:773:5: initialization loop:        /Users/christianb/dev/terraform-provider/pkg/foo/repositories.go:773:5: lookup refers to        /Users/christianb/dev/terraform-provider/pkg/foo/repositories.go:774:18: glob..func6.1 refers to        /Users/christianb/dev/terraform-provider/pkg/foo/artifactory/repositories.go:773:5: lookuptype AutoMapper func(field reflect.StructField, thing reflect.Value) map[string]interface{}var 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()) // recursion error 'cyclic definition'            }            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()        }
查看完整描述

3 回答

?
茅侃侃

TA贡献1842条经验 获得超21个赞

您的函数不能通过名称引用自身,因为它是一个匿名函数。它只有在分配给变量后才会被命名lookup。从词法上讲,这仅在分配的值被完全解析后才会发生。这与普通func声明不同,后者的名称立即可用(这使得递归更加简洁):


func myFunc(arg) result {

    // ... do something ...

    // now we can call the function recursively

    return myFunc(arg)

}

在您的情况下,常规func声明不起作用,因此您需要某种“前向声明”来使名称可用,这需要少量重复:


// forward declare the function

var myFunc func(arg) result


myFunc = func(arg) result {

    // ... do something ...

    // now we can call the function recursively

    return myFunc(arg)

}

要在全球范围内做同样的事情,请参阅Burak 的回答。


查看完整回答
反对 回复 2022-10-10
?
POPMUISE

TA贡献1765条经验 获得超5个赞

问题是初始化循环,而不是递归。您指的是该变量定义中的变量。你可以做:


var lookup func() func(payload interface{}) map[string]interface{}


func init() {

   lookup=func() func(payload interface{}) map[string]interface{} {...}

}


查看完整回答
反对 回复 2022-10-10
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

我按照其他人的建议做了各种排列并遇到了同样的问题。最终,这就是我的工作


type AutoMapper func(field reflect.StructField, thing reflect.Value) map[string]interface{}


func checkForHcl(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{}{}

    }

}


func findInspector(kind reflect.Kind) AutoMapper {

    switch kind {

    case reflect.Struct:

        return checkForHcl(func(f reflect.StructField, t reflect.Value) map[string]interface{} {

            return lookup(t.Interface())

        })

    case reflect.Ptr:

        return checkForHcl(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())

                }

                return map[string]interface{}{

                    field.Tag.Get("hcl"): deref.Interface(),

                }

            }

            return map[string]interface{}{}

        })

    case reflect.Slice:

        return checkForHcl(func(field reflect.StructField, thing reflect.Value) map[string]interface{} {

            return map[string]interface{}{

                field.Tag.Get("hcl"): castToInterfaceArr(thing.Interface().([]string)),

            }

        })

    }

    return checkForHcl(func(field reflect.StructField, thing reflect.Value) map[string]interface{} {

        return map[string]interface{}{

            field.Tag.Get("hcl"): thing.Interface(),

        }

    })

}


func lookup(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)

        typeInspector := findInspector(thing.Kind())

        for key, value := range typeInspector(field, thing) {

            values[key] = value

        }

    }

    return values

}


查看完整回答
反对 回复 2022-10-10
  • 3 回答
  • 0 关注
  • 100 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信