Go语言中的包
Go
语言中的包(Package)是Go
语言组织代码的一种独特形式,它有助于代码的封装、复用和管理.
Go语言中包的概念
Go
语言使用包来组织源代码的,并实现命名空间的管理,任何一个Go
语言程序必须属于一个包,即每个go
程序的开头要写上package <pkg_name>
。
Go
语言包一般要满足如下三个条件:
- 同一个目录下的同级的所有
go
文件应该属于一个包; - 包的名称可以跟目录不同名,不过建议同名;
- 一个
Go
语言程序有且只有一个main
函数,他是Go
语言程序的入口函数,且必须属于main
包,没有或者多于一个进行Go
程序编译时都会报错;
包的引用
关于GOPATH
...
GOPATH
是GO语言使用的一个环境变量,使用绝对路径提供项目的工作目录,适合处理大量 Go语言源码、多个包组合而成的复杂工程。实际使用中,可以先通过命令go env
来查看一下当前的GOPATH
值,然后再决定是不是需要重新设置。
包引用格式
Go包的引入格式常见的有四种,下面以引用fmt
包为例说明:
- 标准引用
import fmt
- 设置别名引用
import format_go fmt
省略方式的引用import . fmt
,这种引用相当于把包fmt
的命名空间合并到当前程序的命名空间了,因此可以直接引用,不用在加上前缀fmt.
- 仅执行包的初始化函数
import _ fmt
另外,当一个Go
程序需要导入多个包时,可以使用单行导入或者多行导入,如下分别列出两种导入形式:
- 单行导入
import "package1"
import "package2`
- 多行导入
import (
"package01"
"package02"
)
另外,导入的包必须要被使用,否则程序编译时也会报错。
包引用初始化流程
假设一个go
语言程序的引入包的顺序是:main-> 包A -> 包B ->包C
,且包A、B、C均实现了init()
函数,那么整个初始化流程顺序则为:C.init -> B.init -> A.init -> main-> 包A -> 包B -> 包C
。
包中标识符的导出
如果一个包要引用另一个包的标识符(比如结构体、变量、常量、函数等),那么首先必须要将其导出,具体做法就是在定义这些标识符的时候保证首字母大写(首字母小写的标识符只能限制在包内引用,有点类似使用Java中使用Public
Private
等来控制成员变量在不同代码中的可访问权限)。另外在被导出的的结构体或者接口中,首字母大写的字段和方法才能被包外访问。
包的作用域
- 包内部的标识符(如变量、常量、类型、函数等)如果首字母大写,则可以被外部包访问,称为导出(Exported)或公开的。
- 如果标识符首字母小写,则仅在同一个包内可见,即为包私有的。
主包和可执行文件
- 每个Go程序都有一个名为
main
的包,这是程序的入口点。main
包包含main()
函数,程序从这里开始执行。 - 只有
main
包可以编译成可执行文件。
Init函数和main函数
init函数
go语言中init
函数用于包(package)
的初始化,该函数是go语言的一个重要特性。
有下面的特征:
1 init函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等
2 每个包可以拥有多个init函数
3 包的每个源文件也可以拥有多个init函数
4 同一个包中多个init函数的执行顺序go语言没有明确的定义(说明)
5 不同包的init函数按照包导入的依赖关系决定该初始化函数的执行顺序
6 init函数不能被其他函数调用,而是在main函数执行之前,自动被调用
main函数
Go语言程序的默认入口函数(主函数):func main()
函数体用{}一对括号包裹。
func main(){
//函数体
}
init函数和main函数的异同
相同点:
两个函数在定义时不能有任何的参数和返回值,且Go程序自动调用。
不同点:
init可以应用于任意包中,且可以重复定义多个。
main函数只能用于main包中,且只能定义一个。
两个函数的执行顺序:
对同一个go文件的init()
调用顺序是从上到下的。
对同一个package中不同文件是按文件名字符串比较“从小到大”顺序调用各文件中的init()
函数。
对于不同的package
,如果不相互依赖的话,按照main包中"先import
的后调用"的顺序调用其包中的init()
,如果package
存在依赖,则先调用最早被依赖的package
中的init()
,最后调用main
函数。
如果init
函数中使用了println()
或者print()
你会发现在执行过程中这两个不会按照你想象中的顺序执行。这两个函数官方只推荐在测试环境中使用,对于正式环境不要使用。