Go语言标识符可见性唯一由首字母大小写决定:大写导出(对外可见),小写包内私有;方法、字段、类型、变量等均遵循此规则,且接收者类型与方法名必须同时导出才可跨包调用。

Go 语言中没有 public、private 关键字,模块可见性完全由标识符的首字母大小写决定——这是唯一规则,且不可绕过。
导出标识符必须首字母大写
只有首字母为大写的常量、变量、函数、类型、字段、方法名才会被导出(即对外可见)。小写字母开头的标识符仅在定义它的包内可访问。
常见错误现象:在其他包中 import 后无法调用某个函数或访问某个字段,检查其首字母是否为小写。
-
MyFunc()✅ 可导出;myFunc()❌ 不可导出 -
UserName✅ 可导出;userName❌ 包内私有 -
type Config struct { Port int }→Port✅ 可被外部访问;若写成port int,则外部无法读写 - 嵌套结构体字段也遵循同样规则:
type Server struct { cfg *config }中cfg小写,即使config类型本身导出了,该字段仍不可见
包级变量和 init 函数的可见性陷阱
init() 函数永远不导出,也不能被显式调用;它只在包初始化时自动执行。而包级变量是否导出,仍只看名字首字母。
立即学习“go语言免费学习笔记(深入)”;
容易忽略的点:即使一个变量是导出的,如果它被初始化为未导出类型的值(比如指向未导出结构体的指针),外部包也无法使用该值的字段或方法。
-
var DefaultClient = &httpClient{}→ 若httpClient是小写类型,则外部无法访问其任何字段或方法,哪怕DefaultClient本身可导出 -
var ErrInvalid = errors.New("invalid")✅ 安全,因为error是导出接口,且errors.New返回的是导出类型实现 - 不要试图通过大写别名“绕过”限制:
type MyConfig = config不会让config变得可导出
跨包调用时方法接收者的影响
方法能否被外部调用,不仅取决于方法名是否导出,还取决于其接收者类型是否导出。两者必须同时满足,方法才真正对外可见。
package data
type user struct { // 小写,未导出
Name string
}
func (u *user) GetName() string { // 方法名导出,但接收者类型未导出
return u.Name
}
type User struct { // 大写,导出
Age int
}
func (u *User) GetAge() int { // ✅ 接收者类型 + 方法名均导出,可跨包调用
return u.Age
}
上面例子中,GetName() 在其他包中不可见,即使你拿到了 *user 实例(你根本拿不到,因为 user 类型不可导出)。
- 接收者是未导出类型 ⇒ 方法不可导出,无论方法名如何
- 接收者是指针或值类型不影响可见性判断,只影响能否赋值或修改
- 接口类型方法签名中的参数/返回值类型也需导出,否则接口本身可能无法被外部完整使用
最易被忽略的是组合嵌入:如果嵌入一个未导出字段(如 unexported unexportedType),即使该类型有导出方法,这些方法也不会“提升”为外部可见。可见性规则不穿透未导出字段边界。










