写点什么

层次分明井然有条,Go lang1.18 入门精炼教程,由白丁入鸿儒,Go lang 包管理机制 (package)EP10

  • 2022 年 8 月 13 日
    北京
  • 本文字数:3559 字

    阅读完需:约 12 分钟

层次分明井然有条,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang包管理机制(package)EP10

Go lang 使用包(package)这种概念元素来统筹代码,所有代码功能上的可调用性都定义在包这个级别,如果我们需要调用依赖,那就“导包”就行了,无论是内部的还是外部的,使用 import 关键字即可。但事情往往没有那么简单,Go lang 在包管理机制上走了不少弯路,虽然 1.18 版本的包管理已经趋于成熟,但前事不忘后事之师,我们还是需要了解一下这段历史。

环境变量

一般情况下,go lang 在系统中会依赖两个环境变量,分别是:GOPATH 和 GOROOT,有点类似于 Python 的解释器目录的概念,GOROOT 这个变量的作用就是为了告诉当前运行的 Go 进程当前 Go 安装路径,当要运行的时候去什么位置找 GoSDK 相关的类。


GOPATH 这个变量的设定是默认所有的项目和引用的第三方包都下载到 GOPATH 的 src 目录下,也就是说,你的代码只要不在 GOPATH 里,就没法编译。我们可以理解这个目录就是项目目录,这一点跟 Python 区别还是挺大的,Python 的 pip 包管理机制至今都是经典的包依赖设计模式。


GOPATH 这种设定方式会导致很多问题,比方说我有很多 go lang 项目,而每个项目又都有自己的 GOPATH 目录,那所有依赖的包就都在项目各自目录下,导致重复包过多,反之,如果大家都用一个 GOPATH 目录,又会带来版本问题,每个项目依赖的包版本不一致,到底怎么进行统筹又是一个问题,这就是 GOPATH 设定早期被人诟病的原因。

Go modules

针对因为 GOPATH 这种反人类的设计而导致的包管理乱象,Go lang 1.11 版本的时候推出了新特性 Go modules。


Go modules 是官方推出的依赖管理工具,Go modules 提供了 3 个重要的功能:


1.go.mod 文件,它和 Node 的 package.json 文件的功能相似,都是记录当前项目的依赖关系。


2.机器生成的传递依赖项描述文件 : go.sum。


3.不再有 GOPATH 的反人类限制,所有代码可以位于电脑的任何路径中。


go lang1.18 早已经集成了 Go modules,但就像golang1.18第一篇精炼教程里写得那样,默认还是反人类的 GOPATH 模式,你想用,得通过命令手动开启:


go env -w GO111MODULE=on
复制代码


为了能够向下兼容维护 go1.11 版本以下的项目,可以设置为兼容模式:


go env -w GO111MODULE=auto
复制代码

三方包管理

三方包指的是外部开源的一些包,而使用 go modules 机制管理三方包相对简单,首先新建一个项目目录,比如 c:/www/test


cd c:/www/test
复制代码


进入项目目录后,初始化项目:


go mod init test
复制代码


系统返回:


C:\Users\liuyue\www\test>go mod init test  go: creating new go.mod: module test    C:\Users\liuyue\www\test>dir      2022/08/12  12:13    <DIR>          .  2022/08/12  12:13    <DIR>          ..  2022/08/12  12:13                21 go.mod                 1 个文件             21 字节                 2 个目录 228,767,113,216 可用字节
复制代码


这里注意项目名和目录名称要吻合,go.mod 文件是开启 modules 的必备配置文件。它记录了当前项目引用的包数据信息。go.mod 文件中定义了以下关键词:


module:用于定义当前项目的模块路径


go:用于设置 Go 版本信息


require:用于设置一个特定的模块版本


exclude:用于从使用中排除一个特定的模块版本


replace:用于将一个模块版本替换为另一个模块版本


接着,运行 go get 命令安装三方包,比如说 gin 框架:


go get github.com/gin-gonic/gin
复制代码


随后编写 main.go 文件,也就是 main 包:


package main    import (    "github.com/gin-gonic/gin"  )    func main() {    d := gin.Default()    d.GET("/", func(c *gin.Context) {      c.JSON(200, gin.H{"message": "hello go 1.18", "data": ""})    })    d.Run("127.0.0.1:5000")  }
复制代码


这里将刚刚安装的三方包导入,然后再 main 函数中调用。


紧接着启动服务:


go run main.go
复制代码


系统返回:


C:\Users\liuyue\www\test>go run main.go  [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.    [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.   - using env:   export GIN_MODE=release   - using code:  gin.SetMode(gin.ReleaseMode)    [GIN-debug] GET    /                         --> main.main.func1 (3 handlers)  [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.  Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.  [GIN-debug] Listening and serving HTTP on 127.0.0.1:5000  [GIN] 2022/08/12 - 12:19:20 | 200 |      3.8876ms |       127.0.0.1 | GET      "/"  [GIN] 2022/08/12 - 12:19:21 | 404 |            0s |       127.0.0.1 | GET      "/favicon.ico"
复制代码


说明三方包的服务已经启动了,访问 http://localhost:5000:



这就是一个 go lang 项目导入三方包的具体流程。


接着我们打开项目中的 go.mod 文件:


module test    go 1.18    require (    github.com/gin-contrib/sse v0.1.0 // indirect    github.com/gin-gonic/gin v1.8.1 // indirect    github.com/go-playground/locales v0.14.0 // indirect    github.com/go-playground/universal-translator v0.18.0 // indirect    github.com/go-playground/validator/v10 v10.10.0 // indirect    github.com/goccy/go-json v0.9.7 // indirect    github.com/json-iterator/go v1.1.12 // indirect    github.com/leodido/go-urn v1.2.1 // indirect    github.com/mattn/go-isatty v0.0.14 // indirect    github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect    github.com/modern-go/reflect2 v1.0.2 // indirect    github.com/pelletier/go-toml/v2 v2.0.1 // indirect    github.com/ugorji/go/codec v1.2.7 // indirect    golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect    golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect    golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect    golang.org/x/text v0.3.6 // indirect    google.golang.org/protobuf v1.28.0 // indirect    gopkg.in/yaml.v2 v2.4.0 // indirect  )
复制代码


三方包 gin 以及 gin 所依赖的三方包都一目了然。

内部包管理

内部包指的是项目内部的包,一般情况下就是自己开发的可复用的包,go modules 也可以对内部包进行管理,在刚刚创建的 test 项目中,新建目录 my:


C:\Users\liuyue\www\test>mkdir my    C:\Users\liuyue\www\test>dir   驱动器 C 中的卷没有标签。   卷的序列号是 0A64-32BF     C:\Users\liuyue\www\test 的目录    2022/08/12  12:39    <DIR>          .  2022/08/12  12:13    <DIR>          ..  2022/08/12  12:18             1,046 go.mod  2022/08/12  12:18             6,962 go.sum  2022/08/12  12:16               228 main.go  2022/08/12  12:39    <DIR>          my                 3 个文件          8,236 字节                 3 个目录 228,568,178,688 可用字节    C:\Users\liuyue\www\test>
复制代码


然后再 my 目录新建一个 my.go 文件:




package my import "fmt" func New() { fmt.Println("我是my包") }
复制代码


这里我们声明包与目录名一致,随后再声明一个 New 函数。


接着改写 main.go 内容:


package main    import (    "fmt"    "test/my"  )    func main() {    fmt.Println("main run")    // 使用my    my.New()  }
复制代码


程序返回:


main run  我是my包
复制代码


触类旁通,如果包不在同一个项目下:




├── moduledemo │ ├── go.mod │ └── main.go └── mypackage ├── go.mod └── mypackage.go
复制代码


这个时候,mypackage 也需要进行 module 初始化,即拥有一个属于自己的 go.mod 文件,内容如下:


module mypackage    go 1.18
复制代码


然后我们在 moduledemo/main.go 中按如下方式导入:


import (      "fmt"      "mypackage"  )  func main() {      mypackage.New()      fmt.Println("main")  }
复制代码

结语

对于 Go lang 的项目来说,如果没有开启 go mod 模式,那么项目就必须放在 GOPATH/src 目录下,项目本身也可以看作为一个本地包,可以被其它 GOPATH/src 目录下的项目引用,同时也可以被 go modules 模式的项目引入,因为 go modules 的原理是先去 GOPATH/src 目录下寻址,如果没有才去指定目录寻址,但反过来,如果是放在 go modules 项目中的本地包,GOPATH/src 目录下的项目就无法引用,因为 GOPATH 规定项目都必须得放在 GOPATH/src 目录下,它只会在 GOPATH/src 目录下寻址,这是我们需要注意的地方。

发布于: 刚刚阅读数: 3
用户头像

专注技术,凝聚意志,解决问题 v3u.cn 2020.12.21 加入

还未添加个人简介

评论

发布
暂无评论
层次分明井然有条,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang包管理机制(package)EP10_Go_刘悦的技术博客_InfoQ写作社区