理解Golang包的import导入机制
1 理解 Go import
Go 中的程序由各种包组成。包依赖于其它包,这些包内置于标准库或者第三方。
包首先需要被导入才能使用包中的导出标识符。这是通过结构体调用 import 声明 来实现的.
import (
"encoding/json"
"errors"
"fmt"
"net"
)
热身
1.1 使用点操作引入包
使用点操作引入包时,可以省略包前缀:
import . "fmt" // fmt 前多了 . 字符
func main() {
Println("hello world!")
}
1.2 别名操作
import (
fs "fmt"
)
func main() {
fs.Println("Hello World!")
}
1.3 _ 操作
由于go在引入包时会调用包中的init方法。所以使用_
操作,主要是为了使用包的init函数,一般用在数据库方面的包中:
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
避免go编译时提示引入了包但未使用
_
操作其实只是引入该包。当导入一个包时,它所有的init()函数就会被执行,但有些时候并非真的需要使用这些包,仅仅是希望它的init()函数被执行而已。这个时候就可以使用_
操作引用该包了。即使用_
操作引用包是无法通过包名来调用包中的导出函数,而是只是为了简单的调用其init函数()。
基础
1.4 import
看一段代码
package csdn
import (
"a/b/c"
"fmt"
)
都会想当然的将import后面的"c"、"fmt"当成包名,将其与c.Func1()和 fmt.Println()中的c
和fmt
认作为同一个语法元素:包名。
但在深入Golang后,很多人便会发现事实上并非如此。比如在使用实时分布式消息平台nsq提供的go client api时:
package csdn
import "github.com/nsqio/nsq"
func main() {
nsq.NewConsumer()
}
使用其提供的export functions时,却用nsq做前缀包名。
你不禁要问:import后面路径中的最后一个元素到底代表的是啥? 是包名还是仅仅是一个路径?
我们知道一个非main包在编译后会生成一个.a文件,用于后续可执行程序链接使用。
Go标准库中的包对应的源码部分路径在:$GOROOT/src
,而标准库中包编译后的.a文件路径在$GOROOT/pkg/darwin_amd64
下。
一个奇怪的问题在我脑袋中升腾起来,编译时,编译器到底用的是**.a还是源码**?
这个可以通过实验验证,提供一个实验思路:
在 GOPATH下创建
testDemo文件夹
,在该目录下创建两个文件夹,这两个子文件夹中创建两个.go
,其中一个import第二个。先 go install 被调用的那个包,之后编译调用者包,生成可执行文件,再执行。
修改被
调用包
,比如修改输出内容…再次执行调用者,会看到修改之后的输出内容.
结论:***(1)在使用第三方包的时候,当源码和.a均已安装的情况下,编译器链接的是源码***
编译器找源码,而不是.a,因此我们要依赖第三方包,就必须搞到第三方包的源码,这也是Golang包管理的一个特点。
(2)所谓的使用第三方包源码,实际上是链接了以该最新源码编译****的临时目录下的.a文件而已。
目录名还是包名
得知编译器在编译过程中依赖的是包源码的路径,Go语言中import后面路径中最后的一个元素到底是包名还是路径名?
通过实验验证,实验思路:
按照Golang语言习惯,一个go package的所有源文件放在同一个目录下,且该目录名与该包名相同,比如
server/process
目录下的package为userProcess.go、smsProcess.go、registerProcess.go …共同组成process package的源文件。但目录名与包名也可以不同,做个测试。
process.go内的代码,注意 包名定义为了 test
在main.go中,import 的是包名,而不是路径名 , 出错
。
更换 main.go 中的 import ,将 import 包名 换为import 路径名,正确
。
得到结论:
(3)import后面的最后一个元素应该是路径,就是目录,并非包名。
进阶
import m “lib/math”
Go language specification
中关于import package时列举的一个例子如下:
import "lib/math" math.Sin
import m "lib/math" m.Sin
import . "lib/math" Sin
import m “lib/math” m.Sin 一行,由于lib/math是路径,import语句用m替代lib/math,并在代码中通过m访问math包中的导出函数Sin。
那m到底是包名还是路径呢?既然能通过m访问Sin,那m肯定是包名了,Right!那import m "lib/math"该如何理解呢?
根据上面得出的结论,我们尝试理解一下 :
m
:(4) m 指代的是 lib/math 路径下唯一的那个包。
一个目录下是否可以存在两个包呢?答案是:否
实验思路:
按照上面的思路,在上面的process.go中再创建一个 process2.go 文件。
在 main.go 中 import test “DailyGolang/csdn/csdnTEst/test” 报错
总结
命名为 main 的包,是用来创建可执行的二进制文件。程序的执行是从包 main 开始,通过调用包中也叫做 main 的函数开始。
- 标准包使用的是给定的短路径,如"fmt"、“net/http”
- 自己的包,需要在工作目录(GOPATH)下指定一个目录,improt 导入包,实际上就是基于工作目录的文件夹目录
程序的初始化和执行都起始于main包。如果main包还导入了其它的包,那么就会在编译时将它们依次导入。
有时一个包会被多个包同时导入,那么它只会被导入一次。当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数。
等所有被导入的包都加载完毕了,就会开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数,最后执行main函数。
注意:
import 导入 Go 包有几种方式,用途不同。 代码统一存储在工作目录下,工作目录里边会有很多个包,不同包按目录组织,包下面由多个代码文件组成。导入包时按包的唯一路径进行导入,导入的包默认是必须要使用,如果不使用则编译失败,需要移除,减少不必要代码的引入,当然还有其他使用场景。默认情况下,我们使用文件名做为包名,方便理解。不同包组织不同的功能实现,方便理解。
到此这篇关于“理解Golang包的import导入机制”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!Go语言中import后面路径中最后的一个元素到底是包名还是路径名?
- import后面的最后一个元素应该是路径,就是目录,并非包名。但是很多时候,这个路径名字和包名字相同。
- import m “lib/math” m指代的是lib/math路径下唯一的那个包 ,编译器在这个路径下如果发现了两个包,是不允许的,编译报错。
您可能感兴趣的文章:
golang 之 import 和 package 的使用
Golang(Go语言)包机制的理解
Golang笔记:包管理机制
理解Golang包的import导入机制
Go 语言包管理机制深入分析
Go 中的 init 函数
理解Golang包导入机制
python怎么添加模块
5分钟入门golang module
Golang包管理详解