本文記錄下學(xué)習(xí) golang官方文檔 里 go tools 和包管理相關(guān)知識的筆記。
go tools有些設(shè)計(jì)很讓人困惑,網(wǎng)上文章講不明白,無奈只能看官方文檔
0. 太長不看
盡量用高版本go,最好用1.18以后的版本,不行就1.16
低版本工具鏈一坨* ,而且你還得花精力專門學(xué)習(xí)、記憶低版本工具和高版本工具有啥區(qū)別,邏輯賊繞
1. 環(huán)境變量
https://pkg.go.dev/cmd/go#hdr-Environment_variables
go env 查看生效的配置、修改配置
用go env -w改配置的話,改的是每個(gè)用戶自己的配置文件

下載不到包? 掛代理!
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,全局公用一個(gè)GOPATH很容易導(dǎo)致不同版本的包沖突。
為避免此問題,可以用goland IDE,IDE支持每個(gè)project單獨(dú)配一個(gè)自己的GOPATH。該設(shè)置會被保存在工作目錄的 .idea 目錄下,不會被設(shè)置到環(huán)境變量的 GOPATH 中,但會在編譯時(shí)使用到這個(gè)目錄。
http://c.biancheng.net/view/88.html
2. 常用命令
2.1. go build構(gòu)建
https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies
構(gòu)建生成可執(zhí)行文件。
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編譯運(yùn)行
https://pkg.go.dev/cmd/go#hdr-Compile_and_run_Go_program
例如
# 當(dāng)前目錄
go run .
或者
# 一個(gè)文件
go run hello.go
3. 包管理
3.1. 代碼組織
3.1.1. 模型
- import單元
go代碼是按package(目錄)組織的,作為一個(gè)import單元; - 發(fā)布單元
多個(gè)相關(guān)package組成一個(gè)module,作為一個(gè)發(fā)布單元;
A repository contains one or more modules.
作為對比, nodejs是:
- import單元
nodejs按文件組織,一個(gè)文件是一個(gè)模塊(module, 相當(dāng)于go里的package)
源碼文件里引入依賴,需要寫明白要引的文件 - 發(fā)布單元
整個(gè)項(xiàng)目對應(yīng)一個(gè)package(相當(dāng)于go里的module),需要在package.json里配name和版本。
java是:
- import單元
每個(gè)源碼文件對應(yīng)一個(gè)class, import的時(shí)候import這個(gè)class。即使這個(gè)類里有內(nèi)部類,也是import這個(gè)文件對應(yīng)的類
這么講有點(diǎn)繞,簡單理解成import單元是文件即可 - 發(fā)布單元
用maven的話,每個(gè)maven archifact打出來的jar是一個(gè)發(fā)布單元
python:
- import單元
文件。每個(gè)文件是一個(gè)模塊,見 https://www.liaoxuefeng.com/wiki/1016959663602400/1017454145014176
3.1.2. 包級別訪問控制
首字母小寫: 同package可見
Internal Directories
首字母小寫的可見性比較低,不方便實(shí)現(xiàn)“一個(gè)模塊內(nèi)可見、但是對模塊外不可見”的效果。
使用internal可以實(shí)現(xiàn)這種效果。
以前寫java的時(shí)候就覺得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/
http://www.itdecent.cn/p/760c97ff644c
3.2.1. 倉庫模型
模型是:
vendor --- local module cache --- decentralized remote repo
3.2.1.1. vendor 機(jī)制
每個(gè)module可以有個(gè)目錄、放所有自己依賴的包
go mod vendor 可以用于創(chuàng)建vendor、更新vendor

3.2.1.2. module cache
本地有個(gè)類似于“本地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.
官方叫這個(gè)"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. 去中心化遠(yuǎn)程倉庫
go咋知道每個(gè)倉庫的代碼路徑
https調(diào)倉庫、看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時(shí),有時(shí)候1.17和1.16會有兼容問題導(dǎo)致報(bào)錯(cuò):
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
想用本地的、還沒發(fā)布過的模塊?
https://go.dev/doc/modules/managing-dependencies

想用某個(gè)module的fork版本?

3.2.3. 與module相關(guān)的命令
Module-aware mode vs GOPATH mode
https://go.dev/ref/mod#mod-commands
很多時(shí)候會困惑,為啥同一個(gè)命令在有g(shù)o.mod的目錄敲和沒go.mod目錄敲,效果不一樣?
這是因?yàn)?,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 , 給項(xiàng)目添加依賴
另一種方法是:先在代碼里寫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啥區(qū)別?為什么職責(zé)這么不清楚?
官方文檔說了,建議go get -d ,讓go get只負(fù)責(zé)改go.mod文件,構(gòu)建安裝的事情交給go install來做;以后版本會默認(rèn) -d,廢棄掉2、3步驟
丑陋的設(shè)計(jì) :(
image.png
- 刪除用go get 安裝的package
https://www.cnblogs.com/welhzh/p/8848021.html
3.4. 應(yīng)用管理: go install
https://go.dev/ref/mod#go-install
https://go.dev/doc/modules/managing-dependencies

定位
1.16之后,可以當(dāng)做一鍵下載、安裝命令行工具的包管理器了。
但是,和專業(yè)的包管理器 (app store) 不同的是,go install 不會下載別人已經(jīng)編譯好的程序,而是下載下來后自己編譯,所以慢。做的事情
- (1.16及之后版本) 下載
- 構(gòu)建編譯成二進(jìn)制
- 安裝成本地命令
Non-executable packages are built and cached but not installed.
-
兩種模式: module-aware mode or GOPATH mode
image.png
1.16以前go install不能指定版本,不會自動去下載包,需要你自己用go get下載好;
image.png
1.16以后可以指定版本,可以幫你下載
https://play-with-go.dev/installing-go-programs-directly_go116_en/

非常糟糕的設(shè)計(jì),讓用戶去記憶這if else邏輯
- 使用示例
-
image.png
-
image.png
-
能否用 go install 安裝同一個(gè)應(yīng)用的多個(gè)版本,讓他們共存?
golang 的多版本共存,可以通過項(xiàng)目編譯時(shí)指定 GOPATH 解決。
包的多版本共存,可以通過不同 GOPATH,或者 go modules 機(jī)制解決。
二進(jìn)制應(yīng)用的多版本共存,是 OS 的使用問題,解決方案有:
- 通過改環(huán)境變量解決,例如多版本 JDK 共存:
https://segmentfault.com/a/1190000020083040 - 封裝成版本切換工具,比如上文的 jenv,切換 jdk 版本
https://www.jenv.be/
比如 gvm 可以切換 go版本:
https://zhuanlan.zhihu.com/p/83375992
那么,通過 go install 安裝的應(yīng)用能否方便的切換版本?
不能,沒有現(xiàn)成的工具。頂多每次換版本時(shí),重新 go install 下載、編譯指定版本
參考資料 & 閱讀進(jìn)度
https://www.zhihu.com/question/23486344
-
官網(wǎng) 閱讀進(jìn)度
- How to write Go code
- Effective Go
以前看過,基本全忘了 - Managing dependencies
- Developing modules
https://go.dev/doc/modules/developing
-
Go Modules Reference 閱讀進(jìn)度
- Module-aware commands
- Build commands
- Vendoring
- go get
- go install
- 版本號相關(guān)
- GOSUMDB
- go.mod里面引入新依賴的規(guī)則:間接依賴什么時(shí)候會被引進(jìn)去? 什么時(shí)候會加indirect
- Module-aware commands
-
- go命令reference 閱讀進(jìn)度
- go build
- go run
- 敲
go mod vendor之前還需要go mod tidy么
- go命令reference 閱讀進(jìn)度




