Go语言 使用反射获取结构字段的名称

cnjp1d6j  于 2023-04-27  发布在  Go
关注(0)|答案(7)|浏览(220)

这里打印“Foo”的方式是什么?在这个例子中,打印的是“string”。
http://play.golang.org/p/ZnK6PRwEPp

type A struct {
    Foo string
}

func (a *A) PrintFoo() {
    fmt.Println("Foo value is " + a.Foo)
}

func main() {
    a := &A{Foo: "afoo"}
    val := reflect.Indirect(reflect.ValueOf(a))
    fmt.Println(val.Field(0).Type().Name())
}
suzh9iv8

suzh9iv81#

您需要val.Type().Field(0).Namereflect.Type上的Field方法将返回一个描述该字段的结构体,其中包括名称和其他信息。
没有办法检索表示特定字段值的reflect.Value的字段名,因为这是包含结构的属性。

ghhaqwfi

ghhaqwfi2#

我认为在结构中获取字段名称的更好方法是

func main() {
    a := &A{Foo: "afoo"}
    val := reflect.ValueOf(a).Elem()
    for i:=0; i<val.NumField();i++{
        fmt.Println(val.Type().Field(i).Name)
    }
}

这里有两个提示:
1.在reflect.ValueOf(a)之后使用.Elem(),因为在您的示例中,a是指针。

  1. val.Field(i).Type().Nameval.Type().Field(i).Name完全不同,后者可以获取结构体中字段的名称
    希望对大家有帮助。
    如果您想查看更多案例,请查看my 2mins article
niwlg2el

niwlg2el3#

您需要获取类型定义的字段,而不是值的字段。
http://play.golang.org/p/7Bc7MJikbJ

package main

import "fmt"
import "reflect"

type A struct {
    Foo string
}

func (a *A) PrintFoo() {
    fmt.Println("Foo value is " + a.Foo)
}

func main() {
    a := &A{Foo: "afoo"}
    val := reflect.Indirect(reflect.ValueOf(a))
    fmt.Println(val.Type().Field(0).Name)
}
bvhaajcl

bvhaajcl4#

请注意,此解决方案引用了一个Go模块,该模块现已弃用,并且不再维护。它已于 * 2018年10月11日 * 弃用。

使用structs包的新Names方法,这就更简单了:

package main

import (
    "fmt"

    "github.com/fatih/structs"
)

type A struct {
    Foo string
    Bar int
}

func main() {
    names := structs.Names(&A{})
    fmt.Println(names) // ["Foo", "Bar"]
}
jdg4fx2g

jdg4fx2g5#

package main

import "fmt"
import "reflect"

type A struct {
    Foo string
}

func (a *A) PrintFoo() {
    fmt.Println("Foo value is " + a.Foo)
}

func main() {
    a := &A{Foo: "afoo"}

    //long and bored code
    t := reflect.TypeOf(*a)
    if t.Kind() == reflect.Struct {
        for i := 0; i < t.NumField(); i++ {
            fmt.Println(t.Field(i).Name)
        }
    } else {
        fmt.Println("not a stuct")
    }

    //shorthanded call
    fmt.Println(reflect.TypeOf(*a).Field(0).Name)//can panic if no field exists

}
8fq7wneg

8fq7wneg6#

也可以使用https://github.com/fatih/structs

// Convert the fields of a struct to a []*Field
fields := s.Fields()

for _, f := range fields {
    fmt.Printf("field name: %+v\n", f.Name())
}
9bfwbjaz

9bfwbjaz7#

你可以使用这个函数,它以struct作为第一个参数,然后是它的fields。它返回map类型,使用起来很方便
如果使用来自另一个结构的字段,则不会发生任何情况
如果尝试使用different type,则会导致panic
请注意,根据列表,字段具有序号(从0开始)。结构中的所有字段必须以uppercase开始

func GetStructFieldName(Struct interface{}, StructField ...interface{}) (fields map[int]string) {
    fields = make(map[int]string)
    s := reflect.ValueOf(Struct).Elem()

    for r := range StructField {
        f := reflect.ValueOf(StructField[r]).Elem()

        for i := 0; i < s.NumField(); i++ {
            valueField := s.Field(i)
            if valueField.Addr().Interface() == f.Addr().Interface() {
                fields[i] = s.Type().Field(i).Name
            }
        }
    }
    return fields
}

完整示例和playground

package main

import (
    "fmt"
    "reflect"
)

type Example struct {
    Apple bool
    Pear  int
}

func GetStructFieldName(Struct interface{}, StructField ...interface{}) (fields map[int]string) {
    fields = make(map[int]string)

    for r := range StructField {
        s := reflect.ValueOf(Struct).Elem()
        f := reflect.ValueOf(StructField[r]).Elem()

        for i := 0; i < s.NumField(); i++ {
            valueField := s.Field(i)
            if valueField.Addr().Interface() == f.Addr().Interface() {
                fields[i] = s.Type().Field(i).Name
            }
        }
    }
    return fields
}

func main() {
    e := Example{}

    names := GetStructFieldName(&e, &e.Apple, &e.Pear)

    fmt.Println(names)
    fmt.Println(names[0], names[1])

    for i := range names {
        fmt.Println(names[i])
    }

    /* Output:
    map[0:Apple 1:Pear]
    Apple Pear
    Apple
    Pear
    */
}

相关问题