开发者

Go语言包和包管理详解

目录
  • 1 包简介
    • 1.1 工作空间
    • 1.2 源文件
    • 1.3 包命名
    • 1.4 main 包
  • 2导包
    • 2.1 两种方式
    • 2.2 包的别名
    • 2.3 简洁模式
    • 2.4非导入模式(匿名导入)
    • 2.5 导包的路径
    • 2.6 远程导入
  • 3 初始化 init
    • 3.1 init总结
  • 4 包管理
    • 4.1 演变过程
    • 4.2 Go Model优点
    • 4.3 启用go module
    • 4.4 GOPROXY
  • 5 go mod详解
    • 5.1 go mod命令
    • 5.2 go.mod说明
      • 5.2.1 依赖的版本
      • 5.2.2 replace
    • 5.3 go get
      • 5.3.1 整理依赖
    • 5.4 go mod edit
      • 5.4.1 格式化
      • 5.4.2 添加依赖项
      • 5.4.3 移除依赖项
  • 6 项目中使用go module
    • 6.1 现有项目
      • 6.2 新项目

      1 包简介

      1.1 工作空间

      go语言的工作空间必须由 bin、pkg、src三个目录组成,可以在GOPATH环境变量中添加多个工作空间,但不能和GOROOT相同。通常go get使用第一个工作空间保存下载的第三方库

      workspace
      	|
      	+--- bin // go install 安装目录。
      	|	  |
      	| 	  +--- learn
      	|
      	|
      	+--- pkg // go build ⽣成静态库 (.a) 存放目录。
      	| 	  |
      	|	  +--- darwin_amd64
      	| 			|
      	| 			+--- mylib.a
      	| 					|
      	| 					+--- mylib
      	|						 |
      	|						 +--- sublib.a
      	|
      	+--- src // 项目源码目录。
      		  |
      		  +--- learn
      		  | 	 |
      		  | 	 +--- main.go
      		  |
      		  |
      		  +--- mylib
      				 |
      				 +--- mylib.go
      				 |
      				 +--- sublib
      						|
      						+--- sublib.g
      

      1.2 源文件

      • 编码:源码⽂件必须是 UTF-8 格式,否则会导致编译器出错。
      • 结束:语句以 “;” 结束,多数时候可以省略。
      • 注释:⽀持 “//”、 “/**/” 两种注释⽅式,不能嵌套。
      • 命名:采⽤ camelCasing ⻛格,不建议使⽤下划线。

      1.3 包命名

      ::: tip 包命名惯例

      • 给包命名的惯例是使用包所在目录的名字。这让用户在导入包的时候,就能清晰地知道包名。
      • 尽量使用简介明了的名字,但要避免冲突
      • 包名一般使用单数的形式,但是避免冲突的用的复数比如bytes,errors,strings等
      • 要避免包名有其他含义。比如 temp这种
      • 命名时考虑包名和成员如何配合,尽量减少包名和成员有重复 :::

      1.4 main 包

      • 所有用 Go 语言编译的可执行程序都必须有一个名叫 main 的包。 go语言的编译器会将这种名字的包编译为二进制可执行文件。
      • main包下肯定会有名为main()的函数,main()是程序的入口。
      • 编译完会使用声明 main 包的代码所在的目录的目录名作为二进制可执行文件的文件名

      2导包

      关键字 Import ,进行导包。未使用的导入包,会编译错误。

      2.1 两种方式

      import a import b,…多次导入,以及import(a b c) 批量导入,如果导入的包不使用会报错。

      import "fmt"
      //或者
      import(
      	"fmt"
          "time"
      )
      

      2.2 包的别名

      import(
      	io "fmt"
      )
      io.Println("hello world")http://www.devze.com //别名可以直接用,在包重名时很有用
      

      2.3 简洁模式

      import (
      	. "fmt"  //但是为了别人好看,一般还是不用这种
      )
      func main(){
      	Println("hello")
      }
      

      2.4非导入模式(匿名导入)

      即导入一个包并不使用它。如果不加_,就会出现编译错误。 在这里用下划线 _ 重命名导入的包。只导入,不使用。 但是这个包它进行了初始化,一般在init函数调用,这样做的好处是,有些包我们不显示使用它,但是有可能用到它,或者由用户选择使用哪个。比如 对特定图像驱动包的初始化,在我们格式化转换图片用到。还有 database/sql包,可以先都初始化,让用户选择不同的数据库驱动。

      import _ "test"     //非导入模式:仅让该包执行初始化函数
      

      2.5 导包的路径

      一般情况下是包的相对路径。比如import "learn/test",标准库中的包会在安装 Go 的位置找到,即GOROOT。 Go 开发者创建的包会在 GOPATH 环境变量指定的目录里查找。GOPATH 指定的这些目录就是开发者的个人工作空间。

      2.6 远程导入

      目前的大势所趋是,使用分布式版本控制系统(Distributed Version Control Systems, DVCS) 来分享代码,如 githubLaunchpad 还有 Bitbucket。 Go 语言的工具链本身就支持从这些网站及 类似网站获取源代码。 Go 工具链会使用导入路径确定需要获取的代码在网络的什么地方。

      比如:import "github.com/xxxx/xxx",用导入路径编译程序时, go build 命令会使用 GOPATH的设置,在磁盘上搜索这个包。事实上, 这个导入路www.devze.com径代表一个URL,指向 GitHub上的代码库。如果路径包含 URL,可以使用 Go 工具链从 DVCS 获取包,并把包的源代码保存在GOPATH指向的路径里与 URL 匹配的目录里。这个获取过程 使用 go get 命令完成。

      go get 将获取任意指定的 URL 的包,或者一个已经导入的包所依赖的其 他包。由于 go get的这种递归特性,这个命令会扫描某个包的源码树,获取能找到的所有依赖包。

      3 初始化 init

      每个包可以包含任意多个 init 函数,这些函数都会在程序执行开始的时候被调用。所有被编译器发现的 init 函数都会安排在 main 函数之前执行。 init 函数用在设置包、初始化变量或者其他要在程序运行前优先完成的引导工作。举例如下

       package postgres
       import (
      	 "database/sql"
       )
       func init() { //初始化函数
           //这里省略。。
      	 sql.Register("postgres", new(PostgresDriver))
       }
      

      3.1 init总结

      • 每个源⽂件都可以定义⼀个或多个初始化函数。
      • 编译器不保证多个初始化函数执行次序。
      • 初始化函数在单⼀线程被调用,仅执行⼀次。
      • 初始化函数在包所有全局变量初始化后执行。
      • 在所有初始化函数结束后才执行 main.main。
      • 无法调用初始化函数。

      4 包管理

      4.1 演变过程

      • 2013年:Gedep,社区第一个包管理工具
      • 2015年:vendor,golang官方(golang1.5)
      • 2016、2017 年:dep、manul、Godep、Govendor、godm (Govendor胜出)
      • go module是Go1.11版本之后官方推出的版本管理工具,并且从Go1.1开发者_JAVA入门3版本开始,go module将是Go语言默认的依赖管理工具。

      4.2 Go Model优点

      • 不必须将项目目录放在GOPATH中
      • 不使用vendor目录,而是统一安装到$GOPATH/pkg/mod/cache
      • build/run时,自动析出nhFrBL项目import的包并安装

      4.3 启用go module

      要启用go module支持首先要设置环境变量GO111MODUphpLE,通过它可以开启或关闭模块支持,它有三个可选值:off、on、auto,默认值是auto。 设置GO111MODULE=on之后就可以使用go module了,以后就没有必要在GOPATH中创建项目了,并且还能够很好的管理项目依赖的第三方包信息。 使用 go module 管理依赖后会在项目根目录下生成两个文件go.modgo.sum

      • GO111MODULE=off禁用模块支持,编译时会从GOPATHvendor文件夹中查找包。
      • GO111MODULE=on启用模块支持,编译时会忽略GOPATHvendor文件夹,只根据 go.mod下载依赖。
      • GO111MODULE=auto,当项目在$GOPATH/src外且项目根目录有go.mod文件时,开启模块支持。

      4.4 GOPROXY

      Go1.13之后GOPROXY默认值为proxy.golang.org,在国内是无法访问的,所以十分建议大家设置GOPROXY

      5 go mod详解

      5.1 go mod命令

      常用的go mod命令如下:

      go mod命令描述
      go mod download下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
      go mod edit编辑go.mod文件
      go mod graph打印模块依赖图
      go mod init初始化当前文件夹, 创建go.mod文件
      go mod tidy增加缺少的module,删除无用的module
      go mod vendor将依赖复制到vendor下
      go mod verify校验依赖
      go mod why解释为什么需要依赖

      5.2 go.mod说明

      go.mod文件记录了项目所有的依赖信息,其结构大致如下:

      module github.com/ourlang/studygo/myblog
      go 1.13
      require (
      	github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586
      	github.com/gin-gonic/gin v1.4.0
      	github.com/go-sql-driver/mysql v1.4.1
      	github.com/jmoiron/sqlx v1.2.0
      	github.com/satori/go.uuid v1.2.0
      	google.golang.org/appengine v1.6.1 // indirect
      )
      
      • module用来定义包名
      • require用来定义依赖包及版本
      • indirect表示间接引用

      5.2.1 依赖的版本

      go mod支持语义化版本号,比如go get foo@v1.2.3,也可以跟git的分支或tag,比如go get foo@master,当然也可以跟git提交哈希,比如go get foo@e3702bed2。关于依赖的版本支持以下几种格式:

      gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
      gopkg.in/vmihailenco/msgpack.v2 v2.9.1
      gopkg.in/yaml.v2 <=v2.2.1
      github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
      latest
      

      5.2.2 replace

      在国内访问golang.org/x的各个包都需要翻墙,你可以在go.mod中使用replace替换成github上对应的库。

      replace (
      	golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac
      	golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d
      	golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
      )
      

      5.3 go get

      ::: tip 在项目中执行go get命令可以下载依赖包,并且还可以指定下载的版本。

      • 运行go get -u将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
      • 运行go get -u=patch将会升级到最新的修订版本
      • 运行go get package@version将会升级到指定的版本号version
      • 如果下载所有依赖可以使用go mod download命令。 :::

      5.3.1 整理依赖

      我们在代码中删除依赖代码后,相关的依赖库并不会在go.mod文件中自动移除。这种情况下我们可以使用go mod tidy命令更新go.mod中的依赖关系

      5.4 go mod edit

      5.4.1 格式化

      因为我们可以手动修改go.mod文件,所以有些时候需要格式化该文件。Go提供了一下命令:

      go mod edit -fmt
      

      5.4.2 添加依赖项

      go mod edit -require=golang.org/x/text
      

      5.4.3 移除依赖项

      如果只是想修改go.mod文件中的内容,那么可以运行go mod edit -droprequire=package path,比如要在go.mod中移除golang.org/x/text包,可以使用如下命令

      go mod edit -droprequire=golang.org/x/text
      

      6 项目中使用go module

      6.1 现有项目

      如果需要对一个已经存在的项目启用go module,可以按照以下步骤操作:

      • 在项目目录下执行go modpython init,生成一个go.mod文件。
      • 执行go get,查找并记录当前项目的依赖,同时生成一个go.sum记录每个依赖库的版本和哈希值

      6.2 新项目

      对于一个新创建的项目,我们可以在项目文件夹下按照以下步骤操作:

      • 执行go mod init 项目名命令,在当前项目文件夹下创建一个go.mod文件。
      • 手动编辑go.mod中的require依赖项或执行go get自动发现、维护依赖。

      以上就是Go语言包和包管理详解的详细内容,更多关于Go语言包及管理的资料请关注我们其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜