Go反射通过reflect.Type和reflect.Value获取变量类型与值;2. 可遍历结构体字段并读取标签,常用于JSON解析和ORM映射。

Go语言的反射(Reflection)机制允许程序在运行时动态获取变量的类型信息和值,并能操作其内容。反射在编码通用库、序列化、ORM框架等场景中非常有用。下面从基础到高级,通过完整示例带你掌握Golang反射的核心用法。
1. 基础:获取类型与值
反射的核心是 reflect.Type 和 reflect.Value。使用 reflect.TypeOf 和 reflect.ValueOf 可分别获取变量的类型和值。
示例:
package mainimport ( "fmt" "reflect")func main() { var x int = 42 t := reflect.TypeOf(x) v := reflect.ValueOf(x) fmt.Println("类型:", t) // int fmt.Println("值:", v) // 42 fmt.Println("种类:", t.Kind()) // int}
注意:Kind() 表示底层数据结构(如 int、struct、slice),而 Type() 是具体类型名。
2. 结构体反射:遍历字段与获取标签
反射常用于处理结构体,比如解析 JSON 或数据库映射。我们可以遍历字段、读取结构体标签(tag)。
立即学习“go语言免费学习笔记(深入)”;
type User struct { Name string `json:"name" validate:"required"` Age int `json:"age"`}func inspectStruct(s interface{}) { t := reflect.TypeOf(s) v := reflect.ValueOf(s) if t.Kind() != reflect.Struct { fmt.Println("输入必须是结构体") return } for i := 0; i < t.NumField(); i++ { field := t.Field(i) value := v.Field(i) jsonTag := field.Tag.Get("json") validateTag := field.Tag.Get("validate") fmt.Printf("字段: %s, 类型: %s, 值: %v, json标签: %s, validate标签: %sn", field.Name, field.Type, value.Interface(), jsonTag, validateTag) }}func main() { u := User{Name: "Alice", Age: 30} inspectStruct(u)}
输出:
字段: Name, 类型: string, 值: Alice, json标签: name, validate标签: required
字段: Age, 类型: int, 值: 30, json标签: age, validate标签:
3. 修改值:使用指针与可设置性(Settable)
要通过反射修改变量,原始变量必须传入指针,且需使用 Elem() 获取指针指向的值。
func modifyValue(i interface{}) { v := reflect.ValueOf(i) // 必须是指针且可设置 if v.Kind() != reflect.Ptr || !v.Elem().CanSet() { fmt.Println("需要传入可设置的指针") return } e := v.Elem() // 获取指针指向的值 switch e.Kind() { case reflect.Int: e.SetInt(100) case reflect.String: e.SetString("Modified") }}func main() { var name string = "Original" var age int = 20 modifyValue(&name) modifyValue(&age) fmt.Println(name) // Modified fmt.Println(age) // 100}
4. 调用方法:MethodByName 与 Call
反射可以动态调用结构体的方法,前提是方法是导出的(首字母大写)。
type Greeter struct{}func (g Greeter) SayHello(name string) string { return "Hello, " + name}func (g Greeter) SayGoodbye() { fmt.Println("Goodbye!")}func callMethod(obj interface{}, methodName string, args ...interface{}) []reflect.Value { v := reflect.ValueOf(obj) method := v.MethodByName(methodName) if !method.IsValid() { panic("方法不存在") } in := make([]reflect.Value, len(args)) for i, arg := range args { in[i] = reflect.ValueOf(arg) } return method.Call(in)}func main() { g := Greeter{} result := callMethod(g, "SayHello", "Bob") fmt.Println(result[0].String()) // Hello, Bob callMethod(g, "SayGoodbye") // Goodbye!}
5. 高级应用:实现通用字段设置器
结合字段标签与反射,我们可以实现一个通用的“字段填充器”,根据 map 数据自动填充结构体。
func fillFromMap(obj interface{}, data map[string]interface{}) { v := reflect.ValueOf(obj) if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { panic("obj 必须是指向结构体的指针") } v = v.Elem() t := v.Type() for i := 0; i < t.NumField(); i++ { field := t.Field(i) jsonTag := field.Tag.Get("json") if key, ok := data[jsonTag]; ok { f := v.Field(i) if f.CanSet() { val := reflect.ValueOf(key) if f.Type() == val.Type() { f.Set(val) } } } }}func main() { u := User{} data := map[string]interface{}{ "name": "Charlie", "age": 25, } fillFromMap(&u, data) fmt.Printf("%+vn", u) // {Name:Charlie Age:25}}
这个模式在 JSON 反序列化、配置加载等场景非常实用。
6. 安全与性能提示
反射虽然强大,但有代价:
性能较低,避免在热路径频繁使用 编译期类型检查失效,容易出错 需注意可设置性(CanSet)、指针传递、零值等问题
建议:仅在必要时使用反射,优先考虑接口或代码生成方案(如 stringer、protoc-gen-go)。
基本上就这些。掌握反射,你就拥有了Go语言的“元编程”能力,能写出更灵活的通用代码。
以上就是Golang反射完整示例 从基础到高级应用的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1399100.html
微信扫一扫
支付宝扫一扫