
go反射
获取对象信息
简单场景
go
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{Name: "Alice", Age: 30}
t := reflect.TypeOf(p)
fmt.Println("Type:", t.Name()) // Person
fmt.Println("Kind:", t.Kind()) // struct
// 遍历字段
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("Field: %s, Type: %s, Tag: %s\n",
field.Name, field.Type, field.Tag.Get("json"))
}
}
text
Type: Person
Kind: struct
Field: Name, Type: string, Tag: name
Field: Age, Type: int, Tag: age
比较复杂的tag
go
package main
import (
"fmt"
"reflect"
"strings"
)
type User struct {
Name string `json:"name" validate:"required,min=2" gorm:"size:255"`
Age int `json:"age" validate:"gte=0,lte=150"`
Email string `json:"email" validate:"required,email"`
}
func main() {
var u User
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("字段: %s\n", field.Name)
// 获取 validate tag
validateTag := field.Tag.Get("validate")
if validateTag == "" {
fmt.Println(" 无 validate 标签")
continue
}
fmt.Printf(" 原始 validate tag: %s\n", validateTag)
// 解析 validate tag 中的多个规则
rules := parseValidateTag(validateTag)
for k, v := range rules {
if v == "" {
fmt.Printf(" 规则: %s\n", k)
} else {
fmt.Printf(" 规则: %s=%s\n", k, v)
}
}
fmt.Println()
}
}
// 解析 validate tag,如 "required,min=2" -> map[required:true min:2]
func parseValidateTag(tag string) map[string]string {
rules := make(map[string]string)
parts := strings.Split(tag, ",")
for _, part := range parts {
kv := strings.Split(part, "=")
key := kv[0]
if len(kv) == 1 {
rules[key] = "" // 如 required
} else {
rules[key] = kv[1] // 如 min=2
}
}
return rules
}
text
字段: Name
原始 validate tag: required,min=2
规则: min=2
规则: required
字段: Age
原始 validate tag: gte=0,lte=150
规则: gte=0
规则: lte=150
字段: Email
原始 validate tag: required,email
规则: required
规则: email
封装通用的工具解析tag
go
// main.go
package main
import (
"fmt"
"reflect"
"strings"
)
// 示例结构体,包含复杂的 validate tag
type User struct {
Name string `json:"name" validate:"required,min=2,max=50"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"gte=0,lte=150"`
Active bool `json:"active" validate:"omitempty,boolean"`
Roles []string `json:"roles" validate:"dive,oneof=admin user guest"` // dive 表示验证切片内部元素
Profile string `json:"profile" validate:"-"` // - 表示跳过
}
func main() {
var u User
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("字段名: %s\n", field.Name)
// 获取 validate tag 的原始字符串
tagValue := field.Tag.Get("validate")
if tagValue == "" || tagValue == "-" {
fmt.Println(" ⚠️ 无 validate 规则")
fmt.Println()
continue
}
fmt.Printf(" 原始 tag: %s\n", tagValue)
// 解析成规则列表
rules := ParseTagRules(tagValue)
// 打印每条规则
for key, value := range rules {
if value == "" {
fmt.Printf(" 🔹 %s (无参数)\n", key)
} else {
fmt.Printf(" 🔹 %s = %q\n", key, value)
}
}
fmt.Println()
}
}
// ParseTagRules 将如 "required,min=6,gte=0" 的 tag 解析为 map[key]value
// 支持: required (flag), min=6 (key-value)
func ParseTagRules(tag string) map[string]string {
rules := make(map[string]string)
// 按逗号分割
parts := strings.Split(tag, ",")
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" || part == "-" {
continue
}
// 判断是否有 =
if equalIndex := strings.Index(part, "="); equalIndex > 0 {
key := part[:equalIndex]
value := part[equalIndex+1:]
rules[key] = value
} else {
// 没有 =,就是 flag 类型,值设为空字符串表示存在
rules[part] = ""
}
}
return rules
}
text
字段名: Name
原始 tag: required,min=2,max=50
🔹 min = "2"
🔹 max = "50"
🔹 required (无参数)
字段名: Email
原始 tag: required,email
🔹 required (无参数)
🔹 email (无参数)
字段名: Age
原始 tag: gte=0,lte=150
🔹 gte = "0"
🔹 lte = "150"
字段名: Active
原始 tag: omitempty,boolean
🔹 omitempty (无参数)
🔹 boolean (无参数)
字段名: Roles
原始 tag: dive,oneof=admin user guest
🔹 dive (无参数)
🔹 oneof = "admin user guest"
字段名: Profile
⚠️ 无 validate 规则
使用框架实现复杂tag校验
go
// main.go
package main
import (
"fmt"
"log"
"github.com/go-playground/validator/v10"
)
// 初始化 validator
var validate *validator.Validate
func init() {
validate = validator.New()
}
// 登录请求结构体
type LoginReq struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=6"`
Age int `json:"age" validate:"gte=0,lte=150"` // 年龄 0-150
Role string `json:"role" validate:"oneof=admin user guest"` // 角色必须是其中之一
}
func main() {
// 场景1:测试一个合法的请求
fmt.Println("✅ 测试合法请求:")
validReq := LoginReq{
Email: "alice@example.com",
Password: "123456",
Age: 25,
Role: "user",
}
err := validate.Struct(validReq)
if err != nil {
log.Println("校验失败:", err)
} else {
fmt.Println("通过校验:", validReq)
}
// 场景2:测试非法请求(邮箱格式错误 + 密码太短)
fmt.Println("\n❌ 测试非法请求:")
invalidReq := LoginReq{
Email: "not-an-email", // ❌ 邮箱格式错误
Password: "123", // ❌ 密码太短
Age: 200, // ❌ 年龄超标
Role: "hacker", // ❌ 角色非法
}
err = validate.Struct(invalidReq)
if err != nil {
// 类型断言:将 error 转为 validator.ValidationErrors 以获取详细信息
if validationErrors, ok := err.(validator.ValidationErrors); ok {
fmt.Println("详细校验错误:")
for _, e := range validationErrors {
fmt.Printf("字段: %s, Tag: %s, 值: %v, 条件: %s\n",
e.Field(), e.Tag(), e.Value(), e.Param())
}
} else {
fmt.Println("未知错误:", err)
}
} else {
fmt.Println("意外通过校验:", invalidReq)
}
}
text
✅ 测试合法请求:
通过校验: {alice@example.com 123456 25 user}
❌ 测试非法请求:
详细校验错误:
字段: Email, Tag: email, 值: not-an-email, 条件:
字段: Password, Tag: min, 值: 123, 条件: 6
字段: Age, Tag: lte, 值: 200, 条件: 150
字段: Role, Tag: oneof, 值: hacker, 条件: admin user guest
获取并修改值(需传指针)
go
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
// 调用
p := Person{Name: "Alice", Age: 30}
modifyValue(&p)
fmt.Println(p) // {Bob 30}
}
func modifyValue(i interface{}) {
v := reflect.ValueOf(i)
// 必须是指针才能修改
if v.Kind() != reflect.Ptr || !v.Elem().CanSet() {
panic("need a pointer to a settable value")
}
e := v.Elem() // 解引用
if e.Kind() == reflect.Struct {
nameField := e.FieldByName("Name")
if nameField.CanSet() {
nameField.SetString("Bob")
}
}
}
利用反射执行方法
go
package main
import (
"fmt"
"reflect"
)
type Greeter struct{}
func (g Greeter) SayHello(name string) {
fmt.Println("Hello,", name)
}
func callMethod(obj interface{}, methodName string, args ...interface{}) {
v := reflect.ValueOf(obj)
method := v.MethodByName(methodName)
in := make([]reflect.Value, len(args))
for i, arg := range args {
in[i] = reflect.ValueOf(arg)
}
method.Call(in)
}
func main() {
// 调用
g := Greeter{}
callMethod(g, "SayHello", "World") // Hello, World
}