Go语言 包的基本概念

 
Go语言 包的基本概念
Go语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种高级的代码复用方案。Go语言中为我们提供了很多内置包,如 fmt、os、io 等。
包时结构化代码的一种方式:每个程序都是由包(通常简称为pkg)的概念组成,可以使用自身的包或者从其他包中导入内容
如同其他一些编程语言中的类库或者命名空间的概念,每个Go文件有且仅属于一个包。一个包可以由许多以 .go为扩展名的源文件组成,因此文件名和包名一般来说都是不同的。
必须在源文件中非注释的第一行指明这个文件属于与哪个包 package pacakgeName 语句,通过该语句声明自己所在的包。package main 则表示一个可独立执行的程勋,每个Go应用程序都包含一个名为main的包。
一个应用程序可以包含不同的包,而且即使只使用main包,也不必包所有的代码都写在一个巨大的文件里:可以使用一些较小的文件,并且在每个文件非注释的第一行使用package main来指明这些文件文件都属于main包。如果打算编译报名不是main的源文件,如 pack1,编译后产生的对象文件将会是pack1.a而不是可执行程序。另外,要注意的是所有的包名都应该使用小写字母
 
标准库
在Go的安装文件里包含了一些可以直接使用的包,即标准库。在Windows 下,标准库的位置在Go根目录下的子目录pkg\windoes_amd64中;在Linux下,标准库在Go根目录的子目录 pkg\linux_amd64中.
一般情况下,标准包会存放在$GOROOT/pkg/\$GOOS_GOARCH/目录下. GO的标准库包含了大量的包,(如:fmt 和os),但是也可以创建自己的包
如果想要构建一个程序,则包和包内的文件够必须以正确的顺序进行编译。包的依赖关系决定了器构建顺序。
属于同一个包的源文件必须全部一起被编译,一个包即是编译时的一个单元,因此根据惯例,每个目录都只包含一个包
如果对一个包进行更改或者重新编译,所有引用了这个包的客户端程序都必须全部重新编译
Go中的包模型采用了显示依赖关系的机制来达到快速编译的目录。编译器会从后缀名为.go的对象文件(需要且只需要这个文件)中提取传递依赖关系型的信息
如果A.go 依赖B.go,而B.go 又依赖C.go:
  • 编译C.go,B.go,然后是A.go
  • 为了编译A.go ,编译器读取的是B.go,而不是C.go
这种机制对于编译大型的项目时可以显著提升编译速度
 
示例
在目录example3 下,有目录cat 和main 。 在 cat 目录下有cat.go文件。 在main目录下有main.go文件
复制//cat.go 文件 package cat import "fmt" var Name string = "Tom" var Age int = 5 //初始化函数 func init() { fmt.Println("this is cat package") fmt.Println("init 函数修改前", Name, Age) Name = "jack" Age = 3 fmt.Println("init 函数修改后", Name, Age) }
复制//main.go文件 package main import ( "dev_code/day9/example3/cat" "fmt" ) //调用其他包,程序加载顺序 cat.go中全局变量-->cat.go中的init()函数--->main.go中的main()函数 func main() { fmt.Println("猫的名字:", cat.Name) fmt.Println("猫的年龄:", cat.Age) } //执行main.go文件 输出结果: this is cat package init 函数修改前 Tom 5 init 函数修改后 jack 3 猫的名字: jack 猫的年龄: 3
 
 
程序执行顺序
Go程序 的执行(程序启动)顺序如下:
  1. 按顺序导入所有被main包引用的其他包,然后在每个包中执行如下流程
  2. 如果该包又导入了其他包,则从第一部开始递归执行,但是每个包只会被导入一次
  3. 然后一相反的顺序在每个包中初始化常量和变量,如果该包含有init 函数的话,则调用该函数。
  4. 在完成这一切后,main也执行同样的过程。最后调用执行程序
 
在example5 目录下有demo包,main包,test包。 在demo包中有demo.go文件。在main包中有main.go文件。在test包中有test.go文件
复制//demo.go文件 package demo import "fmt" var Name string = "this is demo package " var Age int = 20 func init() { fmt.Println("this is demo init()") fmt.Println("demo.package.Nam:", Name) fmt.Println("demo.package.Age:", Age) Name = "this is demo New" Age = 200 fmt.Println("demo.package.Nam:", Name) fmt.Println("demo.package.Age:", Age) }
复制//test.go文件 package test import ( // 在引用的包前面加上 _ 表示只加载这个包,但是不进行引用包里的函数和变量 _ "dev_code/day9/example4/demo" "fmt" ) var Name string = "this is test package" var Age int = 10 func init() { fmt.Println("this is test init()") fmt.Println("test.package.Nam:", Name) fmt.Println("test.package.Age:", Age) Name = "this is test New" Age = 100 fmt.Println("test.package.Nam:", Name) fmt.Println("test.package.Age:", Age) }
复制//main.go文件 package main import ( "dev_code/day9/example4/test" "fmt" ) func main() { //main --->test--->demo fmt.Println("main.package", test.Name) fmt.Println("main.package", test.Age) } //执行main.go文件输出结果: this is demo init() demo.package.Nam: this is demo package demo.package.Age: 20 demo.package.Nam: this is demo New demo.package.Age: 200 this is test init() test.package.Nam: this is test package test.package.Age: 10 test.package.Nam: this is test New test.package.Age: 100 main.package this is test New main.package 100

 

 

 
导入包时空白标识符的作用
如果导入了一个包,却没由使用它,则会在构建时引发错误,如imported andnot used
所以,我们可以使用空白标识符_ 来解决
 
方法一:
声明一个全局空白标识符(在main()函数之前),该标识符从 未使用的包中访问符号。
复制package main import "os" var _ = os.Open func main() { }
 
方法二:
在未使用的包前加上一个空白标识符。只初始化加载该包,而不去使用该包的函数和变量
复制package main import _ "os" func main() { }
 
包的别名
在不同的父目录下,存在相同名字的包。比如,在example4和example5目录下,都有cat 包。那么,不管是导入,还是使用包里的函数或者变量,都很不方便,容易混淆。
此时我们可以在导入包的时候,在前面加上包的别名,在使用的使用,使用别名调用即可
复制package main //导入fmt 包,同时,设置a 为fmt 包的别名 import a "fmt" func main() { //在使用时,使用别名进行调用 a.Println("通过包的别名进行调用") } //输出结果: 通过包的别名进行调用
posted @ 2022-03-27 19:24  十一没有撤退可言!  阅读(135)  评论(0编辑  收藏  举报