本文介绍在 go 中利用反射机制,从包含嵌入指针(如 *a)的结构体(如 b)出发,安全获取并操作其底层结构体 a 的字段,重点解决“如何穿透指针嵌入层访问被嵌入类型的公开字段”这一典型反射需求。
在 Go 反射中,当结构体嵌入的是指针类型(例如 *A),直接调用 reflect.Value.FieldByName() 并不能自动解引用——它仅按字段名查找当前层级的导出字段,而 *A 本身是一个指针字段,其值是 reflect.Value 类型的指针对象。要访问 A 的字段(如 Field_1),必须先解引用该嵌入指针,再进入其指向的结构体。
核心步骤如下:
以下为完整可运行示例:
package main
import (
"fmt"
"reflect"
)
type A struct {
Field_1 string
}
type B struct {
*A // 嵌入 *A,字段名隐式为 "A"
}
func getEmbeddedStructFields(v reflect.Value, embeddedTypeName string) (reflect.Value, bool) {
field := v.FieldByName(embeddedTypeName)
if !field.IsValid() || field.Kind() != reflect.Ptr {
return reflect.Value{}, false
}
if field.IsNil() {
return reflect.Value{}, false
}
elem := field.Elem()
if !elem.IsValid() || elem.Kind() != reflect.Struct {
return reflect.Value{}, false
}
return elem, true
}
func main() {
b := B{A: &A{"initial"}}
fmt.Println("Initial value:", *b.A) // {initial}
v := reflect.ValueOf(&b).Elem()
// 安全获取嵌入的 *A 并解引用
aVal, ok := getEmbeddedStructFields(v, "A")
if !ok {
panic("failed to get embedded *A")
}
// 访问 A 的字段
f1 := aVal.FieldByName("Field_1")
if !f1.IsValid() || !f1.CanInterface() {
panic("Field_1 is not accessible")
}
fmt.Println("Field_1 through reflection:", f1.String()) // "initial"
// 修改字段值(需可寻址且可设置)
if f1.CanSet() {
f1.SetString("works")
}
fmt.Println("After modified through reflection:", *b.A) // {works}
}⚠️ 注意事项:

掌握这一模式,即可灵活处理多层嵌入、指针嵌入等复杂结构体反射场景,是构建通用序列化器、校验器或 ORM 映射工具的关键基础。推荐阅读官方经典教程:The Laws of Reflection 深入理解反射本质。