3

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

 2 years ago
source link: https://www.cnblogs.com/v3ucn/p/16583818.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

层次分明井然有条,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 |[97;42m 200 [0m|      3.8876ms |       127.0.0.1 |[97;44m GET     [0m "/"  
[GIN] 2022/08/12 - 12:19:21 |[90;43m 404 [0m|            0s |       127.0.0.1 |[97;44m GET     [0m "/favicon.ico"

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

20220812120832_91053.png

这就是一个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目录下寻址,这是我们需要注意的地方。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK