go中struct导出需类型名和字段名均首字母大写,缺一则外部不可用;json反序列化要求字段导出,否则值为零;只读需方法封装而非小写字段;嵌入不改变字段可见性。

Go 中 struct 名称不导出,字段再大写也没用
如果 type config struct(小写首字母),那整个类型对外不可见——哪怕它里面所有字段都叫 Host、Port、Timeout,其他包连声明变量都做不到:var c config 会直接报错 undefined: config。
真正起作用的是两层可见性:结构体本身要导出(Config),其字段也要导出(Host),缺一不可。
- 结构体未导出 → 外部无法声明、初始化、接收或返回该类型
- 结构体已导出但字段未导出 → 类型可用,但字段访问失败(编译错误)
- 嵌入未导出结构体(如
inner Inner)→ 即使Inner有导出字段,outer.inner.Field仍非法,因为inner字段本身不可见
JSON 反序列化失败?先检查字段是否导出
常见现象:json.Unmarshal 不报错,但目标 struct 字段值全为零值(0、空字符串、nil)——大概率是字段名首字母小写了。
JSON 解析器使用反射读写字段,而 Go 的反射在跨包时**只能看到导出字段**。未导出字段会被跳过,且不提示警告。
- 错误写法:
Temperatures []struct{ degrees int }→degrees小写,解析后始终为0 - 正确写法:
Temperatures []struct{ Degrees int }或更推荐:type Temperature struct { Degrees int } - 注意:struct 字面量中字段名大小写必须和定义一致;别名类型(如
type Temp Temperature)不影响字段导出状态
想只读不想改?不能靠字段命名,得靠方法封装
Go 没有 readonly 字段语法。把字段设成小写(如 email string)只是让它“不可见”,不是“只读”。真正控制读写权限,得靠方法边界。
- 提供
Email() string方法 → 外部能读,但拿到的是副本,无法修改原字段 - 不提供
SetEmail()→ 外部无写入口,自然只读 - 若字段是切片或 map,
GetItems()必须返回副本(append(make([]T, 0, len(s)), s...)),否则外部可直接改底层数组 - 避免返回私有字段指针(如
func (u *User) EmailPtr() *string),这等于绕过只读约束
嵌入结构体时,字段可见性不“继承”
嵌入(embedding)不是继承,不会改变字段的导出状态。能否访问,只看那个字段原本是不是导出的,以及嵌入字段本身是否导出。
-
type Server struct { HTTP http.Server }→HTTP是导出字段,http.Server是导出类型,所以s.HTTP.Addr合法 -
type Server struct { http http.Server }→http字段未导出,s.http.Addr编译失败,哪怕http.Server.Addr是导出的 -
type Server struct { Logger logger.Logger }→ 若logger.Logger是未导出类型(type logger struct),即使它内部有Log()方法,也无法通过s.Logger.Log()调用
最容易被忽略的点:嵌入字段的可见性独立于被嵌入类型的可见性。一个导出字段里嵌了未导出类型,照样寸步难行。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











