乐趣区

关于go:层次分明井然有条Go-lang118入门精炼教程由白丁入鸿儒Go-lang包管理机制packageEP10

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:

这就是一个 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 目录下寻址,这是咱们须要留神的中央。

退出移动版