【问题标题】:golang recursively reflect both type of field and valuegolang 递归地反映字段和值的类型
【发布时间】:2017-12-06 08:21:50
【问题描述】:

在 golang 中,我想通过一个结构递归地反映,获取字段的名称、类型和值。

这里的代码帮我反映golang recurisive reflection

问题是当我尝试提取值时,当我将值反映在 ptr 值上时,我总是感到恐慌。 是否可以同时反映两种类型,并继续传递值,直到我到达原语,然后打印字段名称、类型和值?

这是我修改的代码:

    func printType(prefix string, t reflect.Type, v reflect.Value visited map[reflect.Type]bool) {

    // Print the name of this type with opening ( for description.
    fmt.Printf("%s (", t)

    // Traverse elements, adding to description as we go.
elems:
    for {
        switch t.Kind() {
        case reflect.Ptr:
            fmt.Print("ptr to ")
        case reflect.Slice:
            fmt.Print("slice of ")
        case reflect.Array:
            fmt.Printf("array with %d elements of ", t.Len())
        default:
            break elems
        }
        t = t.Elem()
    }

    // Print the kind of the type and the closing ) of the description.
    // In the case of a struct, we print the names of the fields and recurse.
    switch t.Kind() {
    case reflect.Struct:
        fmt.Printf("struct with %d fields)\n", t.NumField())
        if visited[t] {
            // Don't blow up on recursive type definition.
            break
        }
        visited[t] = true
        prefix += "    "
        for i := 0; i < t.NumField(); i++ {
            f := t.Field(i)
            // Get value for field
            fieldValue := v.Field(i)

            fmt.Print(prefix, f.Name, " ")
            printType(prefix, f.Type, fieldValue, visited)
        }
    default:
        fmt.Printf("%s) : %s\n", t.Kind(), v)
    }
}

当我运行它时,我在调用 fieldValue := v.Field(i) 时会感到恐慌 关于如何实现这一目标的任何想法?

谢谢

【问题讨论】:

    标签: go reflection


    【解决方案1】:

    试试这个:

    func printValue(prefix string, v reflect.Value, visited map[interface{}]bool) {
    
        fmt.Printf("%s: ", v.Type())
    
        // Drill down through pointers and interfaces to get a value we can print.
        for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
            if v.Kind() == reflect.Ptr {
                // Check for recursive data
                if visited[v.Interface()] {
                    fmt.Println("visted")
                    return
                }
                visited[v.Interface()] = true
            }
            v = v.Elem()
        }
    
        switch v.Kind() {
        case reflect.Slice, reflect.Array:
            fmt.Printf("%d elements\n", v.Len())
            for i := 0; i < v.Len(); i++ {
                fmt.Printf("%s%d: ", prefix, i)
                printValue(prefix+"   ", v.Index(i), visited)
            }
        case reflect.Struct:
            t := v.Type() // use type to get number and names of fields
            fmt.Printf("%d fields\n", t.NumField())
            for i := 0; i < t.NumField(); i++ {
                fmt.Printf("%s%s: ", prefix, t.Field(i).Name)
                printValue(prefix+"   ", v.Field(i), visited)
            }
        case reflect.Invalid:
            fmt.Printf("nil\n")
        default:
            fmt.Printf("%v\n", v.Interface())
        }
    }
    

    由于可以从值中获取类型,因此无需将类型传递给打印函数。

    playground example

    【讨论】:

      猜你喜欢
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-24
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      相关资源
      最近更新 更多