Golang(Go语言)包机制的理解
想学习Golang,包肯定是绕不过去的,就像C语言的标准库,这篇文章里,我将为大家介绍关于Go语言包机制的使用、注意事项和原理
<h2>二、package</h2>package遵循以下原则:
<ol><li><code>package</code>是最基本的分发单位和工程管理中依赖关系的体现</li><li>每个Go语言源代码文件开头都必须要有一个<code>package</code>声明,表示源代码文件所属包</li><li>要生成Go语言可执行程序,必须要有名为<code>main</code>的<code>package</code>包,且在该包下必须有且只有一个<code>main</code>函数</li><li>同一个路径下只能存在一个<code>package</code>,一个<code>package</code>可以由多个源代码文件组成</li></ol>按照我个人的理解,一个目录就是一个包,该目录下的所有文件必须属于同一个包。
<h2>三、import</h2> <h3>1. 作用与写法</h3><code>import</code>语句的唯一作用就是导入源码文件所依赖的包,而且导入的包必须在源码文件里用到,否则会报错(在VS Code里如果输入一个没有导入的包函数,VS Code会自动导入)
<code>import</code>的写法有两种格式,建议使用第二种,导入包方法如下:
<pre class="has"><code class="language-Go">//第一种 import "package1" import "package2" import "package3" //第二种 improt ( "package1", "package2", "package3" )</code></pre> <h3>2. 原理</h3>跟<code>package</code>类似,<code>import</code>原理遵守以下几个原则:
<ol><li>如果一个<code>main</code>导入其他的包,包会被顺序导入</li><li>如果导入的包(<code>pkg1</code>)依赖其他的包(包<code>pkg2</code>),会首先导入<code>pkg2</code>,然后初始化<code>pkg2</code>中的常量与变量,如果pkg2中有init函数,会自动执行init</li><li>所有包导入完成后才会对<code>main</code>的常量和变量进行初始化,然后执行<code>main</code>中的<code>init</code>函数(如果有的话),最后执行<code>main</code>函数</li><li>如果一个包被导入多次实际上只会导入一次</li></ol>关于上面第三条规的<code>import</code>多重依赖的流程如下图所示
<h3>3. import别名</h3> <pre class="has"><code class="language-Go">import iii "fmt" // 此处省略一些代码... iii.Println("hello")</code></pre>如果别名是<code>.</code>的话,则可以这样调用(一般不建议这样使用)
<pre class="has"><code class="language-Go">import . "fmt" // 此处省略一些代码... Println("hello")</code></pre>有一个最特别的情况,如果别名是 <code>_ </code>的话,表示只注册该包(初始化全局常量和变量,且执行其init函数),并不会实际引入该包。
当导入一个包时,它所有的 init() 函数就会被执行。有些时候我们并非真的需要使用这些包,仅仅是希望它的 init() 函数被执行而已。
举个例子,如果我们需要处理图像,通常会导入 Go 标准库支持的所有相关的包,但是并不会用到这些包的任何函数。
这里导入了 image/gif、image/jpeg 和 image/png 包,纯粹是为了让它们的 init() 函数被执行(这些 init() 函数注册了各自的图像格式),所有这些包都以下划线作为别名,所以 Go语言不会发出导入了某个包但是没有使用的警告。
四、创建自定义的包
我们创建的自定义的包最好就放在 GOPATH 的 src 目录下(或者 GOPATH src 的某个子目录),如果这个包只属于某个应用程序,可以直接放在应用程序的子目录下,但如果我们希望这个包可以被其他的应用程序共享,那就应该放在 GOPATH 的 src 目录下,每个包单独放在一个目录里,<span style="color:#f33b45;">如果两个不同的包放在同一个目录下,会出现名字冲突的编译错误</span>。
作为惯例,包的源代码应放在一个同名的文件夹下面。同一个包可以有任意多个文件,文件的名字也没有任何规定(但后续名必须是 .go),这里我们假设包名就是 .go 的文件名(如果一个包有多个 .go 文件,则<span style="color:#f33b45;">其中会有一个 .go 文件的文件名和包名相同</span>)。
例如:
<pre class="has"><code class="language-Go">aGoPath/src/stacker/stacker.go aGoPath/src/stacker/stack/stack.go</code></pre>五、理解包导入后的init()函数初始化顺序
Go 语言包会从 main 包开始检查其引用的所有包,每个包也可能包含其他的包。Go 编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
在运行时,被最后导入的包会最先初始化并调用 init() 函数。
通过下面的代码理解包的初始化顺序。
main函数:
<pre class="has"><code class="language-Go">package main import "chapter08/code8-2/pkg1" func main() { pkg1.ExecPkg1() }</code></pre>pkg1包对应的函数:
<pre class="has"><code class="language-Go">package pkg1 import ( "chapter08/code8-2/pkg2" "fmt" ) func ExecPkg1() { fmt.Println("ExecPkg1") pkg2.ExecPkg2() } func init() { fmt.Println("pkg1 init") }</code></pre>pkg2包对应的函数:
<pre class="has"><code class="language-Go">package pkg2 import "fmt" func ExecPkg2() { fmt.Println("ExecPkg2") } func init() { fmt.Println("pkg2 init") }</code></pre> <pre class="has"><code class="language-bash">执行代码,输出如下: pkg2 init pkg1 init ExecPkg1 ExecPkg2</code></pre>参考链接:https://www.jianshu.com/p/bc2bcfaf2a0f
http://c.biancheng.net/view/91.html
➢<span style="color:#f33b45;">了解更多Go语言知识</span>:https://study.163.com/course/introduction/1210620804.htm
到此这篇关于“Golang(Go语言)包机制的理解”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!您可能感兴趣的文章:
想系统学习GO语言(Golang
Go语言学习3----Go语言特色
Golang笔记:语法,并发思想,web开发,Go微服务相关
2018年最全Go语言教程零基础入门到进阶实战视频
关于Golang的介绍
Go语言发展历史、核心、特性及学习路线
go语言和python哪个难
从零开始学习GO语言-搭建Go语言开发环境-快速开发入门第一个小程序
04.Go项目布局-你如何设计项目结构
go语言和php的区别是什么?