必须对变量取地址再调用elem()才能获得可修改的reflect.value:如arr := [3]int{1,2,3},需v := reflect.valueof(&arr).elem();切片同理,且reflect.append后须v.set(newv)写回原变量。
怎么用 reflect.ValueOf 获取切片/数组的可修改值
直接传入切片或数组变量时,reflect.ValueOf 返回的是只读副本;若后续要调用 Set、SetLen 等方法,必须先取地址。否则会 panic:reflect: reflect.Value.Set using unaddressable value。
正确做法是:对变量取地址再反射,且确保原变量本身可寻址(比如不能是字面量或函数返回值):
arr := [3]int{1, 2, 3}
v := reflect.ValueOf(&arr).Elem() // 先取地址,再 .Elem() 得到可寻址的 Value
v.Index(0).SetInt(99) // ✅ 可修改
- 数组必须用
&arr+.Elem(),不能直接reflect.ValueOf(arr) - 切片同理,但注意:切片本身是 header 结构(含指针、长度、容量),
reflect.ValueOf(slice)已包含底层数据指针,仍需&slice才能修改其 header 字段(如长度) - 如果只是读元素,不修改,
reflect.ValueOf(slice)就够了
如何动态追加元素到切片(reflect.Append 的坑)
reflect.Append 不会原地修改原切片变量,而是返回一个新 reflect.Value;你必须手动把它写回原变量,否则追加无效。
slice := []string{"a", "b"}
v := reflect.ValueOf(&slice).Elem()
newV := reflect.Append(v, reflect.ValueOf("c"))
v.Set(newV) // ❗ 必须这一步,否则 slice 还是原来的长度
-
reflect.Append要求第二个参数是reflect.Value,且类型必须和切片元素类型一致,否则 panic:reflect.Append: incompatible kind - 追加多个元素用
reflect.AppendSlice,但传入的也是reflect.Value,且必须是同类型切片 - 底层容量不足时,
Append会自动分配新底层数组——行为和原生append一致,但你无法直接拿到这个新底层数组的指针
怎么安全地遍历反射后的切片或数组元素
用 v.Len() 获取长度,再循环 v.Index(i);但要注意:如果 v 是 nil 切片,v.Len() 返回 0,不会 panic;而 v.Index(0) 会 panic:reflect: slice index out of range。