教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 理解Golang包的import导入机制

理解Golang包的import导入机制

发布时间:2021-05-06   编辑:jiaochengji.com
教程集为您提供理解Golang包的import导入机制等资源,欢迎您收藏本站,我们将为您提供最新的理解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()中的cfmt认作为同一个语法元素:包名

但在深入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 包有几种方式,用途不同。 代码统一存储在工作目录下,工作目录里边会有很多个包,不同包按目录组织,包下面由多个代码文件组成。导入包时按包的唯一路径进行导入,导入的包默认是必须要使用,如果不使用则编译失败,需要移除,减少不必要代码的引入,当然还有其他使用场景。默认情况下,我们使用文件名做为包名,方便理解。不同包组织不同的功能实现,方便理解。

Go语言中import后面路径中最后的一个元素到底是包名还是路径名?

  • import后面的最后一个元素应该是路径,就是目录,并非包名。但是很多时候,这个路径名字和包名字相同。
  • import m “lib/math” m指代的是lib/math路径下唯一的那个包 ,编译器在这个路径下如果发现了两个包,是不允许的,编译报错。
到此这篇关于“理解Golang包的import导入机制”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang 之 import 和 package 的使用
Golang(Go语言)包机制的理解
Golang笔记:包管理机制
理解Golang包的import导入机制
Go 语言包管理机制深入分析
Go 中的 init 函数
理解Golang包导入机制
python怎么添加模块
5分钟入门golang module
Golang包管理详解

[关闭]
~ ~