跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何使用Golang的反射访问结构体字段_Golang反射结构体字段操作方法

必须传结构体指针并调用Elem()获得可寻址、可设置的reflect.Value,字段需导出才能用Field或FieldByName访问和修改,非导出字段仅可读;FieldByName依据Go源码名而非struct tag;StructTag需用tag.Get("key")解析。 怎么用
reflect.Value.Field
读取结构体字段值 必须先拿到结构体的
reflect.Value
,且它得是可寻址的(比如传指针进去),否则调用
Field
会 panic。常见错误是直接对普通变量调用
reflect.ValueOf(s).Field(i)
,这时返回的
Value
是不可寻址的,
Field
调用会失败。 正确做法是:
reflect.ValueOf(&s).Elem().Field(i)
—— 先取地址,再用
Elem()
解引用到原结构体,才能安全访问字段。 如果结构体字段是导出的(首字母大写),
Field(i)
可读可写;非导出字段只能读(且需通过
FieldByName
+
CanInterface()
判断是否能安全转回原始类型)
Field(i)
返回的是
reflect.Value
,要取真实值得调用
Interface()
或对应类型方法(如
Int()
String()
) 索引
i
从 0 开始,超出字段数会 panic,建议先用
NumField()
校验 为什么
reflect.Value.FieldByName
找不到字段 最常见原因是字段名拼写不匹配,或结构体字段没加导出标记。Go 反射只认「导出字段」(即首字母大写),即使你用
json
tag 或
gorm
tag 命名了小写字段,
FieldByName("name")
也找不到
name
字段 —— 它根本不在反射字段列表里。 另一个容易忽略的点:字段名是 Go 源码中的名字,不是 struct tag 里的值。比如
type User struct { Name string `json:"user_name"` }
,要用
FieldByName("Name")
,不是
"user_name"
。 立即学习 “ go语言免费学习笔记(深入) ”; 检查字段是否导出:非导出字段无法通过
FieldByName
访问(哪怕传指针也不行) 大小写必须完全一致,Go 反射不支持忽略大小写的查找 若不确定字段是否存在,用
FieldByNameOK("X")
替代
FieldByName
,避免 panic 如何通过反射修改结构体字段值 只有满足两个条件才能改:字段必须导出,且
reflect.Value
必须可设置(
CanSet() == true
)。这意味着你几乎总是得传结构体指针进去,然后调用
Elem()
。 典型错误是:写
v := reflect.ValueOf(s); v.FieldByName("X").SetString("new")
—— 这里
v
不可设置,
SetString
会 panic。 正确链路:
reflect.ValueOf(&s).Elem().FieldByName("X").SetString("new")
目标字段类型必须和
SetXXX
方法匹配,比如对 int 字段不能用
SetString
,否则 panic 如果字段是 interface{} 类型,需先
Set(reflect.ValueOf(yourValue))
,不能直接
SetString
reflect.StructTag
解析 struct tag 时要注意什么
StructTag
是字符串,得手动解析。别直接用
string(tag)
然后
strings.Split
,因为 tag 值可能含空格、双引号、逗号分隔多个 key:value 对,标准做法是调用
tag.Get("key")
。 例如
`json:"name,omitempty" db:"user_name"`
tag.Get("json")
返回
"name,omitempty"
tag.Get("db")
返回
"user_name"
。注意:如果 key 不存在,
Get
返回空字符串,不会 panic。
StructTag
只在结构体类型(
reflect.Type
)上可用,
reflect.Value
上没有
Tag
方法 获取 tag 要先拿到字段的
reflect.StructField
:用
t.Field(i).Tag
t.FieldByName("X").Tag
如果 tag 值带双引号(如
`json:"id"`
),
Get
返回的内容已自动去引号;但若写成
`json:id`
(无引号),则不合法,go tool 会报错 反射操作结构体字段本身不难,难在错误时机太多、panic 太突然。多数问题都出在「忘了传指针」「误把 tag 当字段名」「对非导出字段强行 set」这三类地方。写的时候多打一行
fmt.Printf("canSet: %v, canInterface: %v\n", v.CanSet(), v.CanInterface())
,能省掉大半调试时间。

相关文章