What would be a good way to dynamically find out what is inside a struct?

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

What would be a good way to dynamically find out what is inside a struct?

问题

如果我有以下的Go结构体:

type Person struct {
	name string
	age  int
}

鉴于我们不知道Person结构体的组成,我们如何以编程的方式找出它的信息呢?我查看了一下,似乎可以使用反射来实现这个目的。

即使只是获取结构体数据的键也是一个开始,可以使用[]string类型来表示,但最理想的情况是还能获取到类型信息。

英文:

So if I have the following struct in Go:

type Person struct {
	name string
	age  int
}

Given that we don't know what consists of the Person struct, how could we find out programmatically? I've had a look around and it seems that reflection could be used to do this perhaps?

Even just getting the keys for the struct data would be a start, as type []string but ideally getting the types back also would be useful.

答案1

得分: 2

你确实可以使用反射来实现这个。你主要需要使用reflect.TypeOfreflect.Type.Fieldreflect.Type.NumFieldreflect.StructField

代码:

package main

import "fmt"
import "reflect"

type Person struct {
    name string
    age  int
}

func main() {
    typ := reflect.TypeOf(Person{})
    for i := 0; i < typ.NumField(); i++ {
        field := typ.Field(i)
        fmt.Println("Field name:", field.Name)
        fmt.Println("Field type:", field.Type)
        fmt.Println()
    }
}

一些注意事项:

  • 这适用于你的包内部和外部的结构体。
  • 如果你需要实际更改或读取数据,请使用reflect.ValueOf,并将其传递给结构体的指针,然后调用Value.Elem()
  • 你不能使用反射在另一个包中设置未导出的字段,否则会引发恐慌(好吧,实际上你可以,但涉及到不安全的操作,而且不太美观),但你可以读取它们。这不是推荐的做法。
  • 在使用反射之前,始终考虑是否真正需要它。目前,你需要有 Go 源代码才能成功导入包,因此如果你只需要知道字段名,直接查看源代码可能更好。如果需要在运行时知道字段名,请问问自己为什么需要,并思考是否有任何可能的解决方法。反射是一个充满了错误和古怪行为的雷区。

Playground 链接

英文:

You can indeed use reflection to do this. You primarily want reflect.TypeOf, reflect.Type.Field, reflect.Type.NumField, and reflect.StructField

Code:

package main

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

type Person struct {
	name string
	age  int
}

func main() {
	typ := reflect.TypeOf(Person{})
	for i := 0; i &lt; typ.NumField(); i++ {
		field := typ.Field(i)
		fmt.Println(&quot;Field name:&quot;, field.Name)
		fmt.Println(&quot;Field type:&quot;, field.Type)
		fmt.Println()
	}
}

Playground link

Some notes:

  • This works for both structs in your package and out of your package
  • If you need to actually change or read data, use reflect.ValueOf and pass it a pointer to the struct, followed by a call to Value.Elem()
  • You cannot set unexported fields in another package via reflect without a panic (well, okay, you can, but it involves unsafe and ain't pretty), but you can read them. This is not recommended.
  • Always consider if you actually need reflection before you use it. At the current time, you need to have Go source to successfully import the package, so if you just need to know field names it may be better to just poke around the source code. If you need to know at runtime, ask yourself why and if there's any possible way around it. Reflect is a landmine of bugs and quirky behavior.

huangapple
  • 本文由 发表于 2014年4月22日 18:38:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/23217146.html
匿名

发表评论

匿名网友

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

确定