反射

2026年9月6日

反射能在运行时问一个值「你是什么类型、里面有什么」。入口是 reflect.TypeOfreflect.ValueOf。框架、ORM、json 都靠它;业务代码能不用就不用。


类型判断

func kindOf(v any) {
	t := reflect.TypeOf(v)
	switch t.Kind() {
	case reflect.Struct:
		fmt.Println("结构体")
	case reflect.Slice:
		fmt.Println("切片")
	case reflect.Map:
		fmt.Println("map")
	default:
		fmt.Println(t.Kind())
	}
}
go

Type 是名义类型(main.User),Kind 是底层种类(struct)。指针的 KindPtr,要看指向什么用 t.Elem()


通过反射获取值

v := reflect.ValueOf(18)
fmt.Println(v.Int())
fmt.Println(v.Interface())
go

KindInt / String / Bool……种类对不上会 panic。接口里的真实值用 Interface() 拿出来再断言。


通过反射修改值

要改外面的变量,必须传指针,再用 Elem() 走到指向的那块:

n := 1
v := reflect.ValueOf(&n).Elem()
if v.CanSet() {
	v.SetInt(2)
}
fmt.Println(n) // 2
go

reflect.ValueOf(n) 拿到的是拷贝,CanSet() 是 false。


结构体反射

读字段和 json tag,没有 tag 就用字段名。下面没处理 -omitempty

func jsonKeys(v any) {
	t := reflect.TypeOf(v)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		key := f.Tag.Get("json")
		if key == "" {
			key = f.Name
		}
		fmt.Println(key)
	}
}
go

修改结构体中某些值

比如 tag 里有 big,就把字符串字段改成大写:

func upperBig(p any) {
	v := reflect.ValueOf(p).Elem()
	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		f := v.Field(i)
		if t.Field(i).Tag.Get("big") == "" || !f.CanSet() {
			continue
		}
		if f.Kind() == reflect.String {
			f.SetString(strings.ToUpper(f.String()))
		}
	}
}
go

调用结构体方法

有名为 Call 的方法就调它:

m := reflect.ValueOf(u).MethodByName("Call")
if m.IsValid() {
	m.Call(nil)
}
go

方法在指针接收者上,就要对指针做 ValueOf


orm 的一个小案例

把结构体扫成「列名 = 值」,给拼 SQL 用:

type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}

func columns(p any) map[string]any {
	v := reflect.ValueOf(p).Elem()
	t := v.Type()
	out := map[string]any{}
	for i := 0; i < v.NumField(); i++ {
		name := t.Field(i).Tag.Get("db")
		if name == "" {
			name = t.Field(i).Name
		}
		out[name] = v.Field(i).Interface()
	}
	return out
}
go

真 ORM 还要处理嵌套、主键、零值跳过,这里只演示反射怎么把字段掏出来。


对反射的一些建议

写框架、序列化、注入这类底层工具,不用反射很难。业务里大量反射不合适:

  • 比直接代码慢一到两个数量级
  • 读起来绕,出错推到运行时
  • 编译期帮不上忙

能用接口、泛型、代码生成解决的,优先那些。


参考文档