Go结构体字段访问必须通过实例名加点号,编译期确定,不支持字符串动态访问;字段首字母小写则包外不可见;匿名字段重名导致提升失效;JSON解析需导出字段加正确json tag,否则为零值。

结构体字段访问必须通过实例变量名加点号
Go 语言中不能像 Python 那样用字符串动态取字段(如 getattr(obj, "Name")),所有字段访问都是编译期确定的。你必须先声明一个结构体实例,再用 实例名.字段名 的方式访问:
type User struct {
Name string
Age int
}
u := User{Name: "Alice", Age: 30}
fmt.Println(u.Name) // ✅ 正确
fmt.Println(u.Age) // ✅ 正确
- 如果字段首字母小写(如
name),则该字段在包外不可见,外部包无法访问 - 结构体字面量初始化时,字段名可省略,但顺序必须与定义一致;推荐显式写出字段名,避免错位
- 访问嵌套结构体字段时,支持链式写法:
user.Profile.Address.City,前提是每一级都非 nil
指针接收者方法里修改字段要小心 nil 指针
当方法接收者是指针类型(func (u *User) SetName(n string)),调用时传入的是结构体指针。但如果该指针为 nil,而方法内部又试图读/写字段,就会 panic:
func (u *User) GetName() string {
return u.Name // panic: invalid memory address or nil pointer dereference
}
var u *User
u.GetName() // ❌ 崩溃
- 在指针接收者方法开头加
if u == nil { return "" }是常见防御写法 - 值接收者方法(
func (u User))不会 panic,但修改字段无效——因为操作的是副本 - 是否用指针接收者,主要看是否需要修改原结构体,以及结构体是否较大(避免拷贝开销)
匿名字段提升后字段名冲突怎么办
Go 支持匿名字段(如 Name string 或 *Person),其字段会被“提升”到外层结构体作用域。但若多个匿名字段含同名字段(比如都叫 ID),编译器会报错:
type A struct{ ID int }
type B struct{ ID int }
type C struct {
A
B
}
c := C{}
// c.ID // ❌ 编译错误:ambiguous selector c.ID
- 必须显式指定层级:
c.A.ID或c.B.ID - 即使只有一个匿名字段有
ID,另一个是普通字段ID2 int,提升仍生效;但一旦重名,提升失效,只能走显式路径 - 接口字段、内嵌接口不触发提升,只有结构体类型的匿名字段才提升
JSON 解析时字段名大小写和 tag 不匹配导致零值
用 json.Unmarshal 解析 JSON 到结构体时,字段必须是导出的(首字母大写),且默认按字段名匹配。但 JSON 键名通常是小写或带下划线,所以几乎总得加 json tag:
立即学习“go语言免费学习笔记(深入)”;
type Config struct {
Port int `json:"port"` // ✅ 匹配 {"port": 8080}
Host string `json:"host"` // ✅ 匹配 {"host": "localhost"}
// Timeout int `json:"timeout"` // 若没写这行,Timeout 字段将永远为 0
}
- 忽略字段用
json:"-";忽略空值用json:",omitempty" - tag 中字段名区分大小写,
json:"Port"不会匹配{"port": 8080} - struct 字段未加 tag 且首字母小写 → 永远无法被 JSON 解析赋值,保持零值










