Go项目开发中的包管理机制

288 阅读4分钟

包和文件命名规范

把相同的功能放到一个目录,称之为包

main包用来生成可执行文件,每个程序只有一个main包

一个文件夹下只能有一个名字的package

同一个名字的package如果存在在多个目录下,则他们是不同的package。如果一个go文件需要同时使用不同目录下的同名package,需要在import这些目录时为每个目录指定一个package的别名。

import后面的其实是GOPATH开始的相对目录路径,包括最后一段。但由于一个目录下只能有一个package,所以import一个路径就等于是import了这个路径下的包。

如果一个目录有子目录,那么子目录和当前目录是不同的两个包

  • go语言代码使用大驼峰和小驼峰命名法
  • go语言包名应该尽量简短,全小写避免大写,无下划线
  • go语言文件名小写字母和下划线,测试文件以_test.go结尾

理解包原理实验

创建golab文件夹

进入项目后通常创建和文件夹或者说是项目名相同的模块,但是这里执行go mod init Golab,这时查看go.mod中第一行显示module Golab

//go.mod
module Golab
​
go 1.21.5

通常情况下此目录下的a.go文件的package会命名为当前文件夹名,这里为了生成可执行文件,使用main包

//a.go
package main
​
import "fmt"func main() {
    fmt.Println("Hello world") 
}

执行go build生成Golab可执行文件

此目录下创建新文件夹golab2,创建b.go

//b.go
package main
​
import "fmt"func main() {
    fmt.Println("Hello world2") 
}

执行go build会生成可执行文件golab2

也就是说在项目根路径下生成的可执行文件命名为module的名字,在其他文件夹下生成的可执行文件的名字为目录的名字

aha@ubuntu20:~$ tree golab
golab
├── a.go
├── Golab
├── golab2
│   ├── b.go
│   └── golab2
└── go.mod

分包开发-自定义依赖包

有两种方式,一种是本地自定义包,一种是把代码推到github上,这里实验本地自定义包

本地自定义包引入1

root@k8s-master:/home/aha/lab# tree Calc/
Calc/
├── algorithm
│   ├── add
│   │   ├── algorithm_add.go
│   │   └── go.mod
│   └── mul
│       ├── algorithm_mul.go
│       └── go.mod
├── Calc
├── go.mod
└── main.go3 directories, 7 files
//go.mod
module Calc
​
go 1.21.5
​
require(
    algorithm/add v0.0.0
    algorithm/mul v0.0.0
)
replace(
    algorithm/add => ./algorithm/add
    algorithm/mul => ./algorithm/mul
)
//main.go
package main
​
import "fmt"
import "algorithm/add"
import "algorithm/mul"func main(){
    var a int = 1;
    var b int = 2;
    c := add.Add(a, b)
    d := mul.Mul(a, b)
    fmt.Println(c, d)
}
//algorithm/add/go.mod
module add
​
go 1.21.5
//algorithm/add/algorithm_add.go
package add
​
func Add(a int, b int) int {
    return a + b
}
//algorithm/mul/go.mod
module mul
​
go 1.21.5
//algorithm/mul/algorithm_mul.go
package mul
​
func Mul(a int, b int) int {
    return a * b
}
# go build
# ./Calc

本地自定义包引入2(推荐)

直接import的时候,以项目的module开头命名即可

比如以下项目结构

.
├── conf
│   └── config.yaml
├── config
│   └── config.go
├── go.mod
├── go.sum
├── main.go
└── README.md

在main.go中要使用config目录下的config.go中的代码,就可以在main.go文件中引入,假设此项目初始化go mod init golab

import "golab/config"

推送到github(待)

go.sum

Golang为了依赖的安全考虑,在go.mod的基础上引入了go.sumgo.sum文件的作用主要是记录项目依赖的hash值,防止被人修改。

go.sum存在的意义在于,我们希望别人或者在别的环境中构建当前项目时所使用依赖包跟go.sum中记录的是完全一致的,从而达到一致构建的目的。

go.sum文件中每行记录有module名、版本和哈希组成,并由空格分开<module> <version> [/go.mod] <hash>

当我们在GOMODULE模式下引入一个新的依赖时,通常会使用go get命令获取该依赖

go get github.com/google/gopacket

go get命令首先会将该依赖包下载到本地缓存目录,下载完后会对该包做哈希运算,并将结果存放在后缀为.ziphash的文件中。如果在项目的根目录中执行go get命令,go get会同步更新go.modgo.sum文件,go.mod中记录的是依赖名及其版本

go.mod和go.sum文件都应该被git仓库管理起来

伪版本

参考https://www.cnblogs.com/failymao/p/15088416.html

修改第三方包

参考https://segmentfault.com/a/1190000040179648

正常go mod tidy后,放在/root/go/pkg/mod/github.com/...目录,将其拷贝到项目的一个空目录下,然后根据需要进行修改

修改完后,修改项目的go.mod,添加一个replace,一个示例如下

replace github.com/aquasecurity/fanal v0.0.0-20220129174924-b9e05fcccc57 => ./src/fanal@v0.0.0-20220129174924-b9e05fcccc57(直接拷贝过来的文件夹)