在 Go 语言中,所有成员在包内均可访问,无论是否在同一源码文件中。但只有名称首字母为大写的成员可导出,在包外可视。
但是在进行代码重构时,我们会将一些内部模块陆续分离开来,以独立包的形式维护。这时,基于首字母大小写的访问权限控制则显示过于粗犷。我们希望这些包的可导出成员仅在特定范围内可访问,而不是向所有用户公开。
内部包机制提供了这种访问权限控制:所有保存在 internal 目录下的包都只能被其父目录下的包(含所有层次的子目录)访问
。
以下是内部包的结构示例:
src/
internalTest/
external/
external.go
internal/
internal.go
test.go
各包文件代码如下:
// internalTest/external/external.go
package external
import "fmt"
func ExternalHello() {
fmt.Println("ExternalHello")
}
// internalTest/internal/internal.go
package internal
import "fmt"
func InternalHello() {
fmt.Println("InternalHello")
}
// internalTest/test.go
package internalTest
import (
"internalTest/external"
"internalTest/internal"
)
func Hello() {
external.ExternalHello()
internal.InternalHello()
}
测试文件:
// main.go
package main
import (
"internalTest"
"internalTest/external"
//"internalTest/internal" // error: use of internal package internalTest/internal not allowed
)
func main() {
internalTest.Hello()
external.ExternalHello()
//internal.InternalHello()
}
运行 main.go,输出如下:
ExternalHello
InternalHello
ExternalHello
如果将 main.go 中的已注释的代码去除注释,运行时会报错:
use of internal package internalTest/internal not allowed
internal 包和 external 包在同一级目录中,external 包首字母为大写的成员在 internalTest/test.go 以及 main.go 中均可以导出;而 internal 包首字母为大写的成员在 internalTest/test.go 中可导出,而在 main.go 中不可导出。
这样 internal 包就可以提供更为精确的访问权限控制。