使用反射获取结构体字段的名称。

huangapple go评论80阅读模式
英文:

Get name of struct field using reflection

问题

在这里打印"Foo"的方法是什么?在这个例子中,打印的是"string"。

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())
}

在这个例子中,通过使用反射(reflection)来获取结构体字段的类型,并打印出来。在这里,字段"Foo"的类型是"string"。

英文:

What is the way of printing "Foo" here? In this example, what prints is "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())
}

答案1

得分: 93

你想要的是 val.Type().Field(0).Namereflect.Type 上的 Field 方法将返回描述该字段的结构体,其中包括名称和其他信息。

无法通过表示特定字段值的 reflect.Value 来检索字段名称,因为字段名称是包含结构体的属性。

英文:

You want val.Type().Field(0).Name. The Field method on reflect.Type will return a struct describing that field, which includes the name, among other information.

There is no way to retrieve the field name for a reflect.Value representing a particular field value, since that is a property of the containing struct.

答案2

得分: 40

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

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是一个指针。
  2. val.Field(i).Type().Nameval.Type().Field(i).Name完全不同。后者可以获取结构体中字段的名称。

希望对你有帮助。

如果你想查看更多示例,请查看我的2分钟文章

英文:

I think the better way to get the fields' name in the struct is

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

There are two tips:

  1. use .Elem() after you reflect.ValueOf(a), because in your case, a is a pointer.
  2. val.Field(i).Type().Name is totally different from val.Type().Field(i).Name. The latter one can get the name of the field in the struct

Hope that it is helpful..

If you want to have a look at more cases, please check my 2mins article

答案3

得分: 32

你需要获取类型定义的字段,而不是值的字段。

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)
}

链接:http://play.golang.org/p/7Bc7MJikbJ

英文:

You need to Get the Field of the Type Definition not of the Value.

http://play.golang.org/p/7Bc7MJikbJ

package main

import &quot;fmt&quot;
import &quot;reflect&quot;

type A struct {
	Foo string
}

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

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

答案4

得分: 29

请注意,此解决方案引用了一个现已弃用且不再维护的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"]
}
英文:

Note that this solution references a Go module which is now deprecated, and is no longer being maintained. It was deprecated as of Oct 11, 2018.

With the new Names method of the structs package it's even easier:

package main

import (
	&quot;fmt&quot;

	&quot;github.com/fatih/structs&quot;
)

type A struct {
	Foo string
	Bar int
}

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

答案5

得分: 4

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"}

    //长而乏味的代码
    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("不是结构体")
    }

    //简写调用
    fmt.Println(reflect.TypeOf(*a).Field(0).Name) //如果没有字段存在,可能会引发恐慌
}
英文:
package main

import &quot;fmt&quot;
import &quot;reflect&quot;

type A struct {
	Foo string
}

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

func main() {
	a := &amp;A{Foo: &quot;afoo&quot;}
	
	//long and bored code
	t := reflect.TypeOf(*a)
	if t.Kind() == reflect.Struct {
		for i := 0; i &lt; t.NumField(); i++ {
			fmt.Println(t.Field(i).Name)
		}
	} else {
		fmt.Println(&quot;not a stuct&quot;)
	}

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

}

答案6

得分: 2

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

// 将结构体的字段转换为 []*Field
fields := s.Fields()

for _, f := range fields {
fmt.Printf("字段名: %+v\n", f.Name())
}

英文:

You can also use https://github.com/fatih/structs

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

for _, f := range fields {
    fmt.Printf(&quot;field name: %+v\n&quot;, f.Name())
}

答案7

得分: 2

你可以使用这个函数,它以struct作为第一个参数,然后是它的fields。它返回map类型,非常方便使用。

如果你使用另一个结构体的字段,不会发生任何事情。

如果你尝试使用不同的类型,会导致panic

注意,字段根据列表有一个序号(从0开始)。结构体中的所有字段都必须以大写字母开头。

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
    */
}
英文:

You can use this function, which takes the struct as the first parameter, and then its fields. It returns the map type, which is convenient to use

If you use fields from another structure, nothing will happen

If you try to use a different type, it will cause panic

Note that the field has an ordinal number according to the list (starting from 0). All fields in the structure must start with 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 &lt; s.NumField(); i++ {
            valueField := s.Field(i)
            if valueField.Addr().Interface() == f.Addr().Interface() {
                fields[i] = s.Type().Field(i).Name
            }
        }
    }
    return fields
}

Full example and playground

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

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 &lt; 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(&amp;e, &amp;e.Apple, &amp;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
    */
}

huangapple
  • 本文由 发表于 2014年6月21日 08:17:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/24337145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定