Go语言中标识符是否导出仅取决于首字母是否为Unicode大写字母:大写即导出(如MyVar、Name),小写或非ASCII大写(如αlpha)则不可导出;结构体字段、函数、变量、常量均遵循此规则,包名和文件路径不适用。

Go语言中标识符是否导出,只看首字母大小写
Go没有public、private等访问修饰符,判断一个变量、函数、结构体字段能否被其他包访问,唯一依据是它的名字首字母是否为大写。首字母大写即导出(public),小写即未导出(private,仅限本包内使用)。
注意:这里的“大写”指Unicode意义上的大写字母(如拉丁大写A-Z、希腊大写Α-Ω等),但实践中几乎只用ASCII的A-Z。Go编译器不检查语义,只做字面首字符判断。
-
MyVar、NewReader、HTTPClient→ 可导出,其他包可通过pkg.MyVar访问 -
myVar、newReader、httpClient→ 不可导出,其他包无法访问,即使同名也无法跨包引用 -
αlpha(首字符是希腊小写α)→ 不导出;Αlpha(首字符是希腊大写Α)→ 导出(但不推荐,可读性差)
结构体字段的导出控制是独立且关键的
结构体本身是否导出,和它内部字段是否导出,是两回事。即使type Config struct是大写导出的,如果字段全小写,外部包仍无法读写这些字段——只能通过其方法间接操作。
常见错误:定义了导出结构体,却忘了把需要暴露的字段也大写,导致外部包拿到空结构体或 panic。
立即学习“go语言免费学习笔记(深入)”;
-
type User struct { Name string; age int }→Name可读写,age完全不可见(哪怕在同一个包里调用user.age也会编译失败) -
func (u *User) Age() int { return u.age }→ 合理封装,外部可通过u.Age()读取,但不能直接赋值 - 嵌套结构体字段:若
type Inner struct { Val int }未导出,即使Outer导出且含inner Inner字段,外部也无法访问outer.inner.Val
包级函数、变量、常量的导出规则完全一致
函数名、全局变量名、常量名是否导出,同样只看首字母。这点容易被忽略,尤其在写工具函数或配置常量时。
-
func DoWork() {}→ 可被otherpkg.DoWork()调用 -
func doWork() {}→ 仅本包可用,其他包调用会报错:cannot refer to unexported name otherpkg.doWork -
const MaxRetries = 3→ 可导出;const maxRetries = 3→ 不可导出,外部包看不到该常量 -
var DefaultClient *http.Client→ 可被外部复用;var defaultClient *http.Client→ 仅本包初始化时可用
大小写规则在文件路径和包名上不生效
包名(package xxx)本身不区分大小写,也不影响导出;go mod init myapp中的myapp可以全小写,不影响功能。真正起作用的只有标识符(函数、类型、变量等)的首字符。
另外,文件系统路径名(如internal/、cmd/)是Go工具链约定,不是语言级访问控制——它们靠go build阶段的目录扫描逻辑实现隔离,和首字母规则无关。
最容易被忽略的是:大小写规则对init()函数无效——它永远不导出,也永远不能被显式调用,只在包初始化时自动执行。无论写成func init()还是func Init(),后者根本不会被当作初始化函数。










