Go中函数可见性由首字母大小写决定:小写为私有,仅包内可调用;大写为公有,可被其他包导入使用;无private/public关键字,全靠命名约定,编译器静态判定。

func 名字首字母小写就是私有函数,仅限本包内调用;首字母大写才是公有函数,可被其他包导入后使用。Go 没有 private 或 public 关键字,全靠命名约定控制可见性。
私有函数的定义方式:首字母小写即可
只要函数名以小写字母开头,它就自动成为包内私有函数,编译器不会导出它,外部包无法访问。
-
func helper() int—— 私有,只能在当前包中调用 -
func calculateTotal() float64—— 私有,哪怕名字长、语义清晰,首字母小写即不可跨包 -
func NewClient() *Client—— 公有,首字母大写,外部可调用
注意:helper 和 calculateTotal 在其他包里写 mylib.helper() 会直接报错:cannot refer to unexported identifier mylib.helper。
为什么不能靠注释或文档“声明”私有?
Go 不识别 // private 这类注释,也不支持类似 Java 的访问修饰符。可见性完全由编译器在词法分析阶段静态判定。
- 即使你给小写函数加了
// Exported for internal use only注释,外部包仍无法调用——不是“不建议”,而是语法上根本不可见 - 如果误把私有函数名改成大写(比如
Helper()),它立刻变成公有 API,且所有依赖它的外部代码都会生效,没有迁移成本提示 - IDE 或
go vet不会警告“这个函数被意外导出了”,必须人工核对首字母
私有函数在包内能做什么?
私有函数是封装逻辑的核心手段,常用于:
立即学习“go语言免费学习笔记(深入)”;
- 重复逻辑抽离:比如多个公有函数共用的校验、序列化、错误构造逻辑
- 避免暴露实现细节:如
parseConfigRaw()封装原始配置解析,只暴露LoadConfig() - 辅助构造器:像
newConn()返回*conn,但conn类型本身是私有的,外部只能通过NewConn()获取 - 测试辅助:包内测试文件(
_test.go)可调用私有函数做白盒测试
关键点:私有函数可以自由访问本包所有私有类型、字段和变量,不受限制。
常见踩坑:大小写混用导致意外导出或调用失败
最容易出问题的是拼写习惯或 IDE 自动补全诱导的大小写错误。
- 把
validateInput()写成ValidateInput()→ 突然变成公有 API,后续想改回小写会破坏下游兼容性 - 在外部包中尝试调用
mylib.doCleanup()→ 编译错误:cannot refer to unexported identifier mylib.doCleanup - 同名函数在不同包中:包 A 有
format(),包 B 也有format(),它们互不影响——因为彼此不可见,不是重载也不是覆盖
真正容易被忽略的,是私有函数一旦被公有函数间接调用,其行为就构成了公有 API 的隐式契约。比如 Save() 内部调用了私有函数 writeToDisk(),那 writeToDisk() 的副作用(如临时文件生成、锁行为)实际已对外暴露,只是名字没导出而已。


















