李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
13.Golang包介绍
Leefs
2022-07-04 PM
756℃
0条
[TOC] ### 前言 ![13.Golang包介绍01.png](https://lilinchao.com/usr/uploads/2022/07/4113744902.png) Go语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种高级的代码复用方案。Go语言中为我们提供了很多内置包,如 fmt、os、io 等。 任何源代码文件必须属于某个包,同时源码文件的第一行有效代码必须是`package pacakgeName `语句,通过该语句声明自己所在的包。 ### 一、概述 Go语言的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称,虽然Go语言没有强制要求包名必须和其所在的目录名同名,但还是建议包名和所在目录同名,这样结构更清晰。 包可以定义在很深的目录中,包名的定义是不包括目录路径的,但是包在引用时一般使用全路径引用。 #### **包的习惯用法** - 包名一般是小写的,使用一个简短且有意义的名称。 - 包名一般要和所在的目录同名,也可以不同,包名中不能包含`- `等特殊符号。 - 包一般使用域名作为目录名称,这样能保证包名的唯一性,比如 GitHub 项目的包一般会放到`GOPATH/src/github.com/userName/projectName `目录下。 - 包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。 - 一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。 ### 二、定义包 我们可以根据自己的需要创建自定义包。一个包可以简单理解为一个存放`.go`文件的文件夹。该文件夹下面的所有`.go`文件都要在非注释的第一行添加如下声明,声明该文件归属的包。 ```go package packagename ``` **说明** + **package**:声明包的关键字 + **packagename**:包名,可以不与文件夹的名称一致,不能包含 `-` 符号,最好与其实现的功能相对应。 另外需要注意一个文件夹下面直接包含的文件只能归属一个包,同一个包的文件不能在多个文件夹下。 包名为`main`的包是应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含`main`包的源代码则不会得到可执行文件。 ### 三、包的引入 #### 3.1 定义 要在当前包中使用另外一个包的内容就需要使用`import`关键字引入这个包,并且import语句通常放在文件的开头,`package`声明语句的下方。 **完整的引入声明语句格式如下:** ```go import importname "path/to/package" ``` **说明** + `importname`:引入的包名,通常都省略。默认值为引入包的包名。 + `path/to/package`:引入包的路径名称,必须使用双引号包裹起来。 + Go语言中禁止循环导入包。 #### 3.2 引入方式 **(1)单行引入** ```go import "fmt" import "sync" ``` **(2)多行引入** ```go import( "fmt" "sync" ) ``` #### 3.3 匿名引入 如果引入一个包的时候为其设置了一个特殊`_`作为包名,那么这个包的引入方式就称为匿名引入。 一个包被匿名引入的目的主要是为了加载这个包,从而使得这个包中的资源得以初始化。 被匿名引入的包中的`init`函数将被执行并且仅执行一遍。 ```go import _ "github.com/go-sql-driver/mysql" ``` 匿名引入的包与其他方式导入的包一样都会被编译到可执行文件中。 需要注意的是,Go语言中不允许引入包却不在代码中使用这个包的内容,如果引入了未使用的包则会触发编译错误。 #### 3.4 别名使用 当引入的多个包中存在相同的包名或者想自行为某个引入的包设置一个新包名时,都需要通过`importname`指定一个在当前文件中使用的新包名。 例如,在引入`fmt`包时为其指定一个新包名`f`。 ```go import f "fmt" ``` 这样在当前这个文件中就可以通过使用`f`来调用`fmt`包中的函数了。 ```go f.Println("Hello world!") ``` #### 3.5 使用点操作 导入一个包后,如果要使用该包中的函数,都要使用 `包名.方法名` 语法进行调用,对于一些使用高频的包,例如 `fmt` 包,每次调用打印函数时都要使用 `fmt.Println()` 进行调用,很不方便。 我们可以在导入包的时,使用 `import . package_path` 语法。从此,我们打印再也不用加 `fmt` 了。 ```go import . "fmt" func main() { Println("hello, world") } ``` 但这种用法,会有一定的隐患,就是导入的包里可能有函数,会和我们自己的函数发生冲突。 ### 四、包的初始化 #### 4.1 init初始化函数 在每一个Go源文件中,都可以定义任意个如下格式的特殊函数: ```go func init(){ // ... } ``` 这种特殊的函数不接收任何参数也没有任何返回值,也不能在代码中主动调用它。当程序启动的时候,`init`函数会按照它们声明的顺序自动执行。 **一个包的初始化过程是按照代码中引入的顺序来进行的,所有在该包中声明的`init`函数都将被串行调用并且仅调用执行一次。** **每一个包初始化的时候都是先执行依赖的包中声明的`init`函数再执行当前包中声明的`init`函数。** 确保在程序的`main`函数开始执行时所有的依赖包都已初始化完成。 ![13.Golang包介绍02.png](https://lilinchao.com/usr/uploads/2022/07/2386337990.png) 每一个包的初始化是先从初始化包级别变量开始的。 例如从下面的示例中我们就可以看出包级别变量的初始化会先于`init`初始化函数。 ```go package main import "fmt" var x int8 = 10 const pi = 3.14 func init() { fmt.Println("x:", x) fmt.Println("pi:", pi) sayHi() } func init() { fmt.Println("第二个init") } func sayHi() { fmt.Println("Hello World!") } func main() { fmt.Println("你好,世界!") } ``` **运行结果** ``` x: 10 pi: 3.14 Hello World! 第二个init 你好,世界! ``` 一个GO源文件中可以定义任意多个`init`函数,`init`函数之间是从上到下顺序执行的。 #### 4.2 包加载过程 在执行 main 包的 mian 函数之前, Go 引导程序会先对整个程序的包进行初始化。 整个执行的流程如下图所示 ![13.Golang包介绍03.gif](https://lilinchao.com/usr/uploads/2022/07/3645202476.gif) **Go语言包的初始化有如下特点** - 包初始化程序从 main 函数引用的包开始,逐级查找包的引用,直到找到没有引用其他包的包,最终生成一个包引用的有向无环图。 - Go 编译器会将有向无环图转换为一棵树,然后从树的叶子节点开始逐层向上对包进行初始化。 - 单个包的初始化过程如上图所示,先初始化常量,然后是全局变量,最后执行包的 `init` 函数。 *附参考文章链接* *https://www.liwenzhou.com/posts/Go/11-package/#autoid-1-0-0* *http://c.biancheng.net/view/5394.html*
标签:
Golang基础
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2222.html
上一篇
12.Golang函数
下一篇
14.Go module介绍
取消回复
评论啦~
提交评论
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
标签云
Azkaban
Redis
Golang基础
Ubuntu
数据结构和算法
排序
Quartz
Linux
Shiro
Flume
JVM
Zookeeper
散列
Spring
DataX
高并发
查找
Hadoop
算法
LeetCode刷题
Jquery
Yarn
GET和POST
DataWarehouse
Jenkins
二叉树
CentOS
Typora
Flink
机器学习
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞