本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net

前言≈

go 之前对第三方包的管理不上心,其他语言比如 python 有 pip,nodejs 有 npm,而 go 却没有一个官方的管理工具。

在 go 1.11 之前,开发者需要要关注 GOPATH 环境变量,这对于开发者来说不友好。

经过几次变更后,go 于 1.12 版本开始正式使用 go Module,go 终于有了一个官方的处理方式,开发者也可以抛弃 GOPATH 了。

本次使用的 go 版本为 1.15.6,建议使用 1.13 或以上的版本,旧的方式就不要再关注了,让它随风而去吧。

  1. go version go1.15.6 darwin/amd64

本次使用的系统为 Ubuntu,实验路径 / opt/golang

  1. root@xxg:/opt/golang# pwd
  2. /opt/golang

第三方包

假设我们有个项目叫 caseshow,我们先创建这个目录,并初始化一下

  1. mkdir caseshow
  2. cd caseshow
  3. go mod init caseshow

此时在 caseshow 目录下会自动产生一个 go.mod 文件,内容如下:

  1. module caseshow
  2. go 1.15

比如我们想使用一个 redis 客户端:github.com/go-redis/redis/v8,在当前路径下直接执行 go get 命令即可:

  1. go get github.com/go-redis/redis/v8

最近访问 github 很慢,可以先设置一下代理

  1. go env -w GO111MODULE=on
  2. go env -w GOPROXY=https://goproxy.io,direct

设置好之后,下载第三方库

  1. root@xxg:/opt/golang/caseshow# go get github.com/go-redis/redis/v8
  2. go: downloading github.com/go-redis/redis v6.15.9+incompatible
  3. go: downloading github.com/go-redis/redis/v8 v8.4.2
  4. go: github.com/go-redis/redis/v8 upgrade => v8.4.2
  5. go: downloading go.opentelemetry.io/otel v0.14.0
  6. go: downloading github.com/cespare/xxhash/v2 v2.1.1
  7. go: downloading github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f

目录下会多一个 go.sum 文件,go.mod 文件里面也多了关于 redis 库的内容

  1. root@xxg:/opt/golang/caseshow# ls
  2. go.mod go.sum
  3. root@xxg:/opt/golang/caseshow# cat go.mod
  4. module caseshow
  5. go 1.15
  6. require github.com/go-redis/redis/v8 v8.4.2 // indirect

之后就可以直接用了,写个 redis.go 测试下:

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/go-redis/redis/v8"
  6. )
  7. var ctx = context.Background()
  8. func ExampleClient() {
  9. rdb := redis.NewClient(&redis.Options{
  10. Addr: "localhost:6379",
  11. Password: "", // no password set
  12. DB: 0, // use default DB
  13. })
  14. err := rdb.Set(ctx, "key", "value", 0).Err()
  15. if err != nil {
  16. panic(err)
  17. }
  18. val, err := rdb.Get(ctx, "key").Result()
  19. if err != nil {
  20. panic(err)
  21. }
  22. fmt.Println("key", val)
  23. val2, err := rdb.Get(ctx, "key2").Result()
  24. if err == redis.Nil {
  25. fmt.Println("key2 does not exist")
  26. } else if err != nil {
  27. panic(err)
  28. } else {
  29. fmt.Println("key2", val2)
  30. }
  31. // Output: key value
  32. // key2 does not exist
  33. }
  34. func main() {
  35. ExampleClient()
  36. }

测试正常:

  1. root@xxg:/opt/golang/caseshow# go run redis.go
  2. key value
  3. key2 does not exist

整个过程没有 GOPATH 什么事。

本地包

在项目开发中会复用本地的一些代码,这就涉及到了本地包的引入。

情况1. 同路径引用其他文件

无需 import,直接使用对应的方法。
go build时,在后面加上要用的文件名即可,比如

  1. go build main.go main_command.go

go run调试时,在后面加上要用的文件名即可,比如

  1. go run main.go main_command.go

情况2. 同目录下

在同路径下不能存在多个 package 名,如果要定义其他的 package,可以创建一个对应名字的目录,把代码放下面,之后再引用。
假设在 caseshow 中有个本地开发的包 mymodule,里面有个方法 Pprint,结构如下

  1. # tree
  2. .
  3. ├── go.mod
  4. ├── go.sum
  5. ├── mymodule
  6. └── pprint.go
  7. └── redis.go
  8. 1 directory, 4 files

pprint.go 的代码如下:

  1. package mymodule
  2. import "fmt"
  3. func Pprint(a string){
  4. fmt.Println("pprint ", a)
  5. }

如果 caseshow 目录下的其他地方要用这个方法,则使用 caseshow + package 名称导入即可。
比如 main.go:

  1. package main
  2. import "caseshow/mymodule"
  3. func main(){
  4. mymodule.Pprint("jack")
  5. }

直接运行:

  1. # go run main.go
  2. pprint jack

情况3. 不同目录下

假设有另一个项目 caselive,与 caseshow 同级,该目录下有个包 yourmodule, 里面有个方法 Yprint:

  1. # tree
  2. .
  3. ├── caselive
  4. ├── go.mod
  5. ├── main.go
  6. └── yourmodule
  7. └── yprint.go
  8. └── caseshow
  9. ├── go.mod
  10. ├── go.sum
  11. ├── main.go
  12. ├── mymodule
  13. └── pprint.go
  14. └── redis.go
  15. 4 directories, 8 files

yprint.go 的内容如下:

  1. package yourmodule
  2. import "fmt"
  3. func Yprint(a string){
  4. fmt.Println("yprint ", a)
  5. }

此时在 caseshow 中要调用 caselive 中 yourmodule 的 Yprint 方法,可以用replace参数来实现。

在 caseshow 的 go.mod 中增加 caselive 的引入:

  1. require mypackage v0.0.0
  2. replace mypackage => ../mypackage

完整内容如下:

  1. module caseshow
  2. go 1.15
  3. require github.com/go-redis/redis/v8 v8.4.2 // indirect
  4. require caselive v0.0.0
  5. replace caselive => ../caselive

之后就能直接调用了:

  1. package main
  2. import "caseshow/mymodule"
  3. import "caselive/yourmodule"
  4. func main(){
  5. mymodule.Pprint("jack")
  6. yourmodule.Yprint("jack")
  7. }

运行测试下:

  1. # go run main.go
  2. pprint jack
  3. yprint jack

参考资料