Go中结构体字段首字母大写才可被包外访问;小写字段包外不可见,JSON序列化时被忽略,嵌入字段不自动继承可见性,方法接收者类型不影响字段访问规则。

结构体字段首字母大写才能被包外访问
Go 语言里没有 public/private 关键字,字段是否能被其他包访问,只看名字首字母是不是大写。小写的字段(比如 name、age)在包外完全不可见,哪怕你用反射也拿不到值——编译器直接不让你通过语法检查。
- 导出字段必须以大写字母开头:
Name、ID、CreatedAt - 非导出字段哪怕加了注释或标签(如
json:"name"),包外也无法读写 - 嵌套结构体的字段可见性独立判断:外层导出、内层未导出,包外仍不能访问内层字段
- 注意拼写:大小写敏感,
URL和Url是两个不同名字,只有前者是导出的(因为U大写,R和L也大写)
包内调用不受字段可见性限制
同一个包里的所有文件,无论 import 路径怎么写、文件名怎么起,都共享同一套作用域。所以包内代码可以自由访问所有字段,不管大小写。
- 包内测试文件(
xxx_test.go)和普通源文件属于同一包,可直接读写小写字段 - 别指望靠“小写字段+包内测试”来绕过设计约束——这反而会让包使用者误以为字段可被外部依赖
- 如果想在包内做内部状态校验,又不想暴露给外部,小写字段 + 包内辅助函数(如
isValid())是合理组合
JSON 序列化时小写字段会被忽略
用 json.Marshal 序列化结构体时,小写字段默认不会出现在输出中,不是 bug,是设计使然——它只处理导出字段。
- 即使加了
json:"name"标签,json.Marshal也不会处理未导出字段 - 常见错误现象:
json.Marshal返回空对象{}或缺失关键字段,往往是因为字段名全小写 - 临时调试可用
fmt.Printf("%+v", v)看原始值,但别把它当序列化替代方案 - 如果真需要序列化非导出字段(比如调试日志),得手动构造 map 或用第三方库(如
mapstructure),但这会打破封装边界
方法接收者类型不影响字段可见性规则
方法能不能被包外调用,取决于方法名是否导出;但它能不能访问结构体字段,只取决于字段本身是否导出——跟接收者是指针还是值类型、是否导出完全无关。
立即学习“go语言免费学习笔记(深入)”;
-
func (u *User) GetName() string { return u.name }—— 方法导出,但u.name是小写字段,包外调用这个方法会编译失败 - 正确写法是让字段也导出:
u.Name,或者把逻辑移到包内函数中 - 别为了“方便包外调用”而把所有字段设为大写——该隐藏的状态(比如缓存、锁、中间计算结果)就该保持小写
- 一个容易被忽略的点:嵌入结构体的字段可见性不继承。比如
type User struct{ DBModel },即使DBModel有导出字段,User的包外使用者也不能直接写u.ID,除非DBModel.ID本身导出且User显式重导出










