教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang(Go语言)包机制的理解

Golang(Go语言)包机制的理解

发布时间:2022-02-11   编辑:jiaochengji.com
教程集为您提供Golang(Go语言)包机制的理解等资源,欢迎您收藏本站,我们将为您提供最新的Golang(Go语言)包机制的理解资源
<h2>一、概述</h2>

  想学习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 标准库支持的所有相关的包,但是并不会用到这些包的任何函数。

<pre class="has"><code class="language-Go">import ( "fmt" "image" "os" "path/filepath" "runtime” _ "image/gif" _ "image/jpeg" _ "image/png" )</code></pre>

这里导入了 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的区别是什么?

[关闭]
~ ~