Go反射需传地址才能修改切片/数组元素:v := reflect.ValueOf(&slice).Elem()使v.CanSet()为true;仅reflect.ValueOf(slice)不可修改,但均可读取元素。

Go 语言的反射(reflect 包)可以让你在运行时检查和操作变量的类型与值,包括数组和切片。但要注意:**反射不能直接修改不可寻址的值,切片本身是引用类型,但其底层数组元素是否可修改,取决于原始变量是否可寻址**。
获取切片/数组的反射值
使用 reflect.ValueOf() 获取值对象。若要后续修改,必须传入地址(如 &slice),否则得到的是不可寻址的副本:
-
错误写法:
v := reflect.ValueOf(mySlice)→v.CanSet()返回false,无法修改元素 -
正确写法:
v := reflect.ValueOf(&mySlice).Elem()→ 得到可寻址的切片值
对数组同理:v := reflect.ValueOf(&myArray).Elem() 才能修改元素。
动态读取元素
无论是否可寻址,只要值有效,就能读取:
立即学习“go语言免费学习笔记(深入)”;
- 用
v.Index(i)获取第i个元素的reflect.Value - 调用
.Interface()转为 interface{},再类型断言获取具体值
示例:
slice := []int{10, 20, 30}
v := reflect.ValueOf(slice)
if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
for i := 0; i < v.Len(); i++ {
elem := v.Index(i).Interface()
fmt.Printf("索引 %d: %v (类型: %s)\n", i, elem, v.Index(i).Kind())
}
}
动态修改元素(需可寻址)
只有通过指针获取的 reflect.Value 才支持修改:
- 确保
v.CanAddr() && v.CanSet()为true - 用
v.Index(i).Set(x)修改第i个元素,其中x是同类型的reflect.Value - 常用构造方式:
reflect.ValueOf(value)或reflect.ValueOf(&value).Elem()
示例(修改切片第 1 个元素为 99):
slice := []string{"a", "b", "c"}
v := reflect.ValueOf(&slice).Elem() // 可寻址切片
if v.CanSet() {
newVal := reflect.ValueOf("99")
v.Index(1).Set(newVal) // 修改索引 1 的元素
}
fmt.Println(slice) // ["a", "99", "c"]
注意事项与常见坑
反射操作切片/数组时容易出错,务必注意:
- 切片的
Len()和Cap()需用v.Len()/v.Cap(),不能直接用len(v) - 修改元素前必须校验
v.Index(i).CanSet(),否则 panic - 向切片追加元素要用
reflect.Append(),返回新切片值;原切片不会自动更新(因 Go 切片是值传递) - 不支持对未导出字段(小写开头)的结构体切片元素进行反射赋值(即使可寻址)










