Go语言内部包–控制包成员的对外暴露
Go 语言中的软件包推荐按照:组织名/项目名 的形式安排软件包的文件目录结构,一般「项目名」文件目录下还会按照功能、抽象约定、具体实现等维度再划分一些子目录。在 Go 语言里包的导入路径不同则被判定为不同的包,所以同一个软件包项目下的「功能一」包依赖「功能二」包里的成员时,那么成员必须是导出成员才能被「功能一」包引用。但是这样一来,其他项目或者其他组织的代码也就都可以使用这个导出的成员了,假如包里的一些成员我们只想在指定的包之间共享而不想对外暴露该怎么办呢? Go 语言内部包这个特性可以让我们实现这个目标。
内部包
Go语言1.4版本后增加了 Internal packages 特征用于控制包的导入,即internal package只能被特定的包导入。
内部包的规范约定:导入路径包含internal
关键字的包,只允许internal
的父级目录及父级目录的子包导入,其它包无法导入。
示例
.
|-- resources
| |-- internal
| | |-- cpu
| | | `-- cup.go
| | `-- mem
| | `-- mem.go
| |-- input
| | |-- input.go
| `-- mainboard.go
|-- prototype
| `-- professional.go
|-- go.mod
|-- go.sum
如上包结构的程序,resources/internal/cpu
和resources/internal/mem
只能被resources
包及其子包resources/input
中的代码导入,不能被prototype
包里的代码导入。当在prototype
包的代码中导入并调用resources/internal/cpu
包的函数时,编译器根据文件的目录结构判断出来prototype
包相对于被导入的包是外部包,所以整个程序会编译失败,报类似下面的错误:
use of internal package /resources/internal/cpu not allowed
总结
internal/
是 go 编译器在编译程序时可以识别的特殊目录名,除非两个包都具有相同的祖先,否则它将阻止另一个包导入internal/
目录下的包。因此,我们将internal/
目录中的软件包称为内部包。
要为项目创建内部包,只需将包文件放在名为internal/
的目录中。当 go 编译器在导入路径中看到带有internal/
的软件包被导入时,它将验证导入包的程序文件是否位于internal/
目录的父级目录,或父级目录的子目录中。
举例来说导入路径为 /a/b/c/internal/d/e/f
的包,只能被位于/a/b/c
目录或者其子目录中的代码引入,而不能被位于/a/b/e
目录或其子目录中的代码引用。