Elem()必须用于Kind为reflect.Ptr的指针类型reflect.Value,否则panic;正确用法是reflect.ValueOf(&v).Elem()以获得可修改值,而非reflect.ValueOf(v).Elem()。
如果你对一个非指针值(比如 int、struct{})调用 Elem(),Go 会直接 panic:“reflect: call of reflect.Value.Elem on int Value”。它只接受 Kind() 为 reflect.Ptr 的值。
&v 传地址,再 reflect.ValueOf(&v).Elem()
reflect.ValueOf(v).Elem() —— 即使 v 是指针变量,ValueOf(v) 拿到的是指针的**值拷贝**(即内存地址),不是指针类型本身;只有 ValueOf(&v) 才能得到 *int 类型的 reflect.Value
rv.Kind() == reflect.Ptr 或 rv.IsNil() 防止空指针解引用想通过反射改原始变量,本质是“写回内存”,而 reflect.ValueOf(x) 默认只拿到一份只读拷贝。只有走指针路径,才能获得可寻址、可修改的 reflect.Value。
reflect.ValueOf(&x) → 得到 *int 类型的 Value.Elem():reflect.ValueOf(&x).Elem() → 得到可修改的 int 类型 Value.SetInt()、.SetString() 等方法var x int = 10 rv := reflect.ValueOf(&x).Elem() // 关键两步:取地址 + Elem() rv.SetInt(42) fmt.Println(x) // 输出 42
Elem() 是精准解引用一层指针;Indirect() 是“尽力而为”:遇到指针就解,遇到 nil 就返回零值,遇到非指针就原样返回。它们适用场景完全不同。
Elem():你**明确知道**输入是单层指针,且需要严格类型控制(比如结构体字段赋值逻辑中)Indirect():处理用户传入的任意 interface{},想“统一拿到底层值”,比如 ORM 映射或通用 JSON 解析器Indirect() 对非指针不报错,但可能掩盖本该失败的逻辑(例如误把 int 当成 *int 处理)当目标是结构体里某个指针字段(如 type User struct{ Name *string }),光靠一次 Elem()

Elem(),最后才能设值。
CanSet() 返回 false,SetString() 会 panic,跟指针无关FieldByName("Name").Elem() 会 panic,必须先 Set(reflect.New(...))
rv.Elem().FieldByName("Name").Elem().SetString("Alice") —— 其中第一个 Elem() 是解函数参数的 *User,第二个才是解 *string
这种嵌套操作容易漏掉任一环节的可寻址性或非 nil 判断,线上 panic 往往就卡在这一步。