本文记录下学习 golang官方文档 里 go tools 和包管理相关知识的笔记。
go tools有些设计很让人困惑,网上文章讲不明白,无奈只能看官方文档
0. 太长不看
尽量用高版本go,最好用1.18以后的版本,不行就1.16
低版本工具链一坨* ,而且你还得花精力专门学习、记忆低版本工具和高版本工具有啥区别,逻辑贼绕
1. 环境变量
https://pkg.go.dev/cmd/go#hdr-Environment_variables
go env 查看生效的配置、修改配置
用go env -w改配置的话,改的是每个用户自己的配置文件
下载不到包? 挂代理!
export GOPROXY=https://goproxy.cn
http://c.biancheng.net/view/5712.html
GOROOT 和 GOPATH
https://stackoverflow.com/questions/7970390/what-should-be-the-values-of-gopath-and-goroot
https://go.dev/doc/code
https://blog.csdn.net/huyoo/article/details/22715307
https://my.oschina.net/achun/blog/134002
在低版本golang中,没有modules或者没开启modules,全局公用一个GOPATH很容易导致不同版本的包冲突。
为避免此问题,可以用goland IDE,IDE支持每个project单独配一个自己的GOPATH。该设置会被保存在工作目录的 .idea 目录下,不会被设置到环境变量的 GOPATH 中,但会在编译时使用到这个目录。
http://c.biancheng.net/view/88.html
2. 常用命令
2.1. go build
构建
https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies
构建生成可执行文件。
When compiling multiple packages or a single non-main package, build compiles the packages but discards the resulting object, serving only as a check that the packages can be built.
2.2. go run
编译运行
https://pkg.go.dev/cmd/go#hdr-Compile_and_run_Go_program
例如
# 当前目录
go run .
或者
# 一个文件
go run hello.go
3. 包管理
3.1. 代码组织
3.1.1. 模型
- import单元
go代码是按package(目录)组织的,作为一个import单元; - 发布单元
多个相关package组成一个module,作为一个发布单元;
A repository contains one or more modules.
作为对比, nodejs是:
- import单元
nodejs按文件组织,一个文件是一个模块(module, 相当于go里的package)
源码文件里引入依赖,需要写明白要引的文件 - 发布单元
整个项目对应一个package(相当于go里的module),需要在package.json里配name和版本。
java是:
- import单元
每个源码文件对应一个class, import的时候import这个class。即使这个类里有内部类,也是import这个文件对应的类
这么讲有点绕,简单理解成import单元是文件即可 - 发布单元
用maven的话,每个maven archifact打出来的jar是一个发布单元
python:
- import单元
文件。每个文件是一个模块,见 https://www.liaoxuefeng.com/wiki/1016959663602400/1017454145014176
3.1.2. 包级别访问控制
首字母小写: 同package可见
Internal Directories
首字母小写的可见性比较低,不方便实现“一个模块内可见、但是对模块外不可见”的效果。
使用internal
可以实现这种效果。
以前写java的时候就觉得java需要这种功能。
go help gopath
https://golang.org/s/go14internal
3.2. modules
https://go.dev/doc/code
https://www.cnblogs.com/rickiyang/p/13874139.html
https://zhuanlan.zhihu.com/p/92992277
https://zhuanlan.zhihu.com/p/60703832
https://tonybai.com/2019/09/21/brief-history-of-go-package-management/
https://www.jianshu.com/p/760c97ff644c
3.2.1. 仓库模型
模型是:
vendor --- local module cache --- decentralized remote repo
3.2.1.1. vendor 机制
每个module可以有个目录、放所有自己依赖的包
go mod vendor 可以用于创建vendor、更新vendor
3.2.1.2. module cache
本地有个类似于“本地maven仓库”的“本地中央仓库”,支持多版本
Module dependencies are automatically downloaded to the pkg/mod subdirectory of the directory indicated by the GOPATH environment variable. The downloaded contents for a given version of a module are shared among all other modules that require that version, so the go command marks those files and directories as read-only.
官方叫这个"module cache"
- 删掉所有module
To remove all downloaded modules, you can pass the -modcache flag to go clean:
- GOPATH and Modules
go help gopath
GOPATH and Modules
When using modules, GOPATH is no longer used for resolving imports.
However, it is still used to store downloaded source code (in GOPATH/pkg/mod)
and compiled commands (in GOPATH/bin).
3.2.1.3. 去中心化远程仓库
go咋知道每个仓库的代码路径
https调仓库、看meta
https://ehang-io.github.io/blog.ehang.io/2020/01/22/%E8%AE%B0%E5%BD%95%E4%B8%80%E6%AC%A1golang%E5%8C%85%E4%B8%8Egithub%E4%BB%93%E5%BA%93%E7%9A%84%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9F%9F%E5%90%8D%E9%85%8D%E7%BD%AE/
https://golang.org/cmd/go/#hdr-Remote_import_paths
3.2.2. go.mod
- go mod tidy
The go mod tidy command adds missing module requirements for imported packages and removes requirements on modules that aren't used anymore.
敲go mod tidy时,有时候1.17和1.16会有兼容问题导致报错:
https://www.cnblogs.com/zjhgx/p/15336147.html
不知道啥意思,我按建议敲命令 go mod tidy -go=1.16 && go mod tidy -go=1.17
解决
- goland 配modules
https://www.cnblogs.com/xiaobaiskill/p/11819071.html
replace
go.mod里可以用replace替换指定包的版本,比如替换成本地版本
https://thewebivore.com/using-replace-in-go-mod-to-point-to-your-local-module/
但是replace只在主模块生效:
https://golang.org/ref/mod#go-mod-file-replace
想用本地的、还没发布过的模块?
https://go.dev/doc/modules/managing-dependencies
想用某个module的fork版本?
3.2.3. 与module相关的命令
Module-aware mode vs GOPATH mode
https://go.dev/ref/mod#mod-commands
很多时候会困惑,为啥同一个命令在有go.mod的目录敲和没go.mod目录敲,效果不一样?
这是因为,go命令有两种模式,Most go commands may run in Module-aware mode or GOPATH mode
3.3. go get
https://go.dev/doc/modules/managing-dependencies
https://go.dev/ref/mod#go-get
- 做的事情
- 改go.mod , 给项目添加依赖
另一种方法是:先在代码里写import ,然后go mod tidy
- builds the packages named on the command line
- Executables will be installed in the directory named by the GOBIN environment variable
- 对比
go install
你看了2、3肯定想喷:这和go install啥区别?为什么职责这么不清楚?
官方文档说了,建议go get -d ,让go get只负责改go.mod文件,构建安装的事情交给go install来做;以后版本会默认 -d,废弃掉2、3步骤
丑陋的设计 :(
- 删除用go get 安装的package
https://www.cnblogs.com/welhzh/p/8848021.html
3.4. 应用管理: go install
https://go.dev/ref/mod#go-install
https://go.dev/doc/modules/managing-dependencies
定位
1.16之后,可以当做一键下载、安装命令行工具的包管理器了。
但是,和专业的包管理器 (app store) 不同的是,go install 不会下载别人已经编译好的程序,而是下载下来后自己编译,所以慢。做的事情
- (1.16及之后版本) 下载
- 构建编译成二进制
- 安装成本地命令
Non-executable packages are built and cached but not installed.
-
两种模式: module-aware mode or GOPATH mode
1.16以前go install不能指定版本,不会自动去下载包,需要你自己用go get下载好;
1.16以后可以指定版本,可以帮你下载
https://play-with-go.dev/installing-go-programs-directly_go116_en/
非常糟糕的设计,让用户去记忆这if else逻辑
- 使用示例
能否用 go install 安装同一个应用的多个版本,让他们共存?
golang 的多版本共存,可以通过项目编译时指定 GOPATH 解决。
包的多版本共存,可以通过不同 GOPATH,或者 go modules 机制解决。
二进制应用的多版本共存,是 OS 的使用问题,解决方案有:
- 通过改环境变量解决,例如多版本 JDK 共存:
https://segmentfault.com/a/1190000020083040 - 封装成版本切换工具,比如上文的 jenv,切换 jdk 版本
https://www.jenv.be/
比如 gvm 可以切换 go版本:
https://zhuanlan.zhihu.com/p/83375992
那么,通过 go install 安装的应用能否方便的切换版本?
不能,没有现成的工具。顶多每次换版本时,重新 go install 下载、编译指定版本
参考资料 & 阅读进度
https://www.zhihu.com/question/23486344
-
官网 阅读进度
- How to write Go code
- Effective Go
以前看过,基本全忘了 - Managing dependencies
- Developing modules
https://go.dev/doc/modules/developing
-
Go Modules Reference 阅读进度
- Module-aware commands
- Build commands
- Vendoring
- go get
- go install
- 版本号相关
- GOSUMDB
- go.mod里面引入新依赖的规则:间接依赖什么时候会被引进去? 什么时候会加indirect
- Module-aware commands
-
- go命令reference 阅读进度
- go build
- go run
- 敲
go mod vendor
之前还需要go mod tidy么
- go命令reference 阅读进度