说明
- 包是代码包装成模块的方式,不同于python(每个模块就是一个文件),go的包是以目录的形式,一个目录是一个模块,包内文件是以源码的形式存在。
- 包也是实现代码复用的一种方式,同时每个包也是一个独立命名空间,从而避免了命名冲突的问题。
定义包
package name //package + 包名
package A/b //错误,包是按单个目录管理的,不需要定义层次关系
个人理解
- 包是以目录的形式管理,一个包就是一个目录,包的内容包含了该目录下的所有代码文件,不包含子目录。
- go的包不包含目录的层次关系,编译也是按单个目录编译的。
- 源码文件中的第一行都需要定义包名,每个包都对应一个独立的名字空间。
- 同一个目录下的源码不能定义不同的package。
- 使用go1.12测试,包名需要和目录名一样,不然会提示找不到包。
嵌套包
- 目录具有层次和嵌套关系,但是包是以单个目录为单位,不同层次的目录名可以一样,所有包名也可能一样,会冲突,导入包时需要设置别名。
包初始化
- 在每个源码文件中都能够定义init函数,包引入时会先执行该函数做初始化。
- 建议用户在一个package中只写一个init函数。
引入包
引入方式
- 普通方式
import (
"fmt"
)
func main(){
fmt.Println("hello go")
}
- 点方式
import (
. "fmt"
)
- 作用:这个包导入之后在你调用这个包的函数时,可以省略前缀的包名,例如:
func main(){
Println("Hello go!")
}
- 别名方式
import (
io "fmt"
)
- 作用:如果导入的两个包,包名相同,可以通过别名的方式进行区分和调用包中函数,例如:
func main(){
io.Println("hello go")
}
- 下划线方式
import (
_ "fmt"
)
- 作用:只执行该包中的init函数,不导入包里面的函数。
包的查找路径。
- go 标准库存在于go工具的安装目录,私人写的包保存在GOPATH目录下,因此查找包时,编译器会在go的安装目录(即GOROOT环境变量的目录)下查找;也会在 GOPATH 指定的工作目录下查找。
- 如果import指定的是绝对路径或者是相对于当前目录的相对路径,编译器也可以找到,但是不建议这样做。
导入包执行顺序
- 每个包可以包含任意多个 init 函数,这些函数都会在程序执行开始的时候被调用。所有被编译器发现的 init 函数都会安排在 main 函数之前执行。init 函数用在设置包、初始化变量或者其他要在程序运行前优先完成的引导工作。
- 程序的初始化和执行都起始于main包。如果main包还导入了其它的包,那么就会在编译时将它们依次导入。
- 有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。
- 当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。
- 等所有被导入的包都加载完毕了,就会开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数(如果存在的话),最后执行main函数。
包的访问权限
- 包本身没有访问权限,但是包中源码成员可以设置访问权限。
- 包内,所有成员都能互相访问;包外,源码中成员以名称首字母大小写决定访问权限,例如:
- public: 首字母大写,可被包外访问
- private: 首字母小写,仅包内成员可以访问
特殊包(main)
- main包是可执行程序的入口包,包中可以有多个文件,但是只能有一个源码文件定义了main函数。
- 使用go1.14.1测试,其它使用和普通包一致。