拜拜了,GOPATH君!新版本Golang的包管理入門教程

Go 1.11和1.12實現了對包管理的初步支持,Go的新依賴管理系統使依賴版本信息明確且易於管理。
Using Go Modules - The Go Bloggit

Golang

新的包管理模式有什麼不一樣?

做爲Go語言的推廣者,經常被問到各類關於Go語言的基礎特性問題。
其中,關於包管理方面的問題會讓我很是尷尬,由於Go的包管理在1.11以前與Python、Node、Java比較起來真的只能算是「僅僅可用」而已。github

由於:golang

  1. 在不使用額外的工具的狀況下,Go的依賴包須要手工下載,
  2. 第三方包沒有版本的概念,若是第三方包的做者作了不兼容升級,會讓開發者很難受
  3. 協做開發時,須要統一各個開發成員本地$GOPATH/src下的依賴包
  4. 引用的包引用了已經轉移的包,而做者沒改的話,須要本身修改引用。
  5. 第三方包和本身的包的源碼都在src下,很混亂。對於混合技術棧的項目來講,目錄的存放會有一些問題

新的包管理模式解決了以上問題shell

  1. 自動下載依賴包
  2. 項目沒必要放在GOPATH/src內了
  3. 項目內會生成一個go.mod文件,列出包依賴
  4. 因此來的第三方包會準確的指定版本號
  5. 對於已經轉移的包,能夠用replace 申明替換,不須要改代碼

開始吧用一個小例子來講明問題!

準備工做

  1. 升級golang 版本到 1.12 Go下載
  2. 添加環境變量 GO111MODULEon 或者auto
GO111MODULE=auto

準備完畢,很是簡單吧!!工具

建立一個項目

首先,在$GOPATH/src路徑外的你喜歡的地方建立一個目錄,cd 進入目錄,新建一個hello.go文件,內容以下學習

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, world!")
}

初始化模塊

在當前目錄下,命令行運行 go mod init + 模塊名稱 初始化模塊ui

go mod init hello

運行完後,會在當前項目目錄下生成一個go.mod 文件,這是一個關鍵文件,以後的包的管理都是經過這個文件管理。加密

官方說明:除了go.mod以外,go命令還維護一個名爲go.sum的文件,其中包含特定模塊版本內容的預期加密哈希
go命令使用go.sum文件確保這些模塊的將來下載檢索與第一次下載相同的位,以確保項目所依賴的模塊不會出現意外更改,不管是出於惡意、意外仍是其餘緣由。 go.mod和go.sum都應檢入版本控制。
go.sum 不須要手工維護,因此能夠不用太關注。

生成出來的文件包含模塊名稱和當前的go版本號spa

module hello

go 1.12

注意:子目錄裏是不須要init的,全部的子目錄裏的依賴都會組織在根目錄的go.mod文件裏命令行

來吧,搞點小事情,看看go.mod怎麼工做的

接下來,讓你的項目依賴一下第三方包
以大部分人都熟悉的beego爲例吧!
修改Hello.go文件:

package main

import "github.com/astaxie/beego"

func main() {
    beego.Run()
}

按照過去的作法,要運行hello.go須要執行go get 命令 下載beego包到 $GOPATH/src

可是,使用了新的包管理就不在須要這樣作了

直接 go run hello.go

稍等片刻… go 會自動查找代碼中的包,下載依賴包,而且把具體的依賴關係和版本寫入到go.mod和go.sum文件中。
查看go.mod,它會變成這樣:

module hello

go 1.12

require github.com/astaxie/beego v1.11.1

require 關鍵子是引用,後面是包,最後v1.11.1 是引用的版本號

這樣,一個使用Go包管理方式建立項目的小例子就完成了。

那麼,接下來,幾個小問題來了

問題一:依賴的包下載到哪裏了?還在GOPATH裏嗎?

不在。
使用Go的包管理方式,依賴的第三方包被下載到了$GOPATH/pkg/mod路徑下。

若是你成功運行了本例,能夠在您的$GOPATH/pkg/mod 下找到一個這樣的包 github.com/astaxie/beego@v1.11.1

問題二: 依賴包的版本是怎麼控制的?

在上一個問題裏,能夠看到最終下載在$GOPATH/pkg/mod 下的包 github.com/astaxie/beego@v1.11.1 最後會有一個版本號 1.11.1,也就是說,$GOPATH/pkg/mod裏能夠保存相同包的不一樣版本。

版本是在go.mod中指定的。

若是,在go.mod中沒有指定,go命令會自動下載代碼中的依賴的最新版本,本例就是自動下載最新的版本。

若是,在go.mod用require語句指定包和版本 ,go命令會根據指定的路徑和版本下載包,
指定版本時能夠用latest,這樣它會自動下載指定包的最新版本;

依賴包的版本號是什麼? 是包的發佈者標記的版本號,格式爲 vn.n.n (n表明數字),本例中的beego的歷史版本能夠在其代碼倉庫release看到Releases · astaxie/beego · GitHub

若是包的做者尚未標記版本,默認爲 v0.0.0

問題三: 能夠把項目放在$GOPATH/src下嗎?

能夠。
可是go會根據GO111MODULE的值而採起不一樣的處理方式
默認狀況下,GO111MODULE=auto 自動模式

  • auto 自動模式下,項目在$GOPATH/src裏會使用$GOPATH/src的依賴包,在$GOPATH/src外,就使用go.mod 裏 require的包
  • on 開啓模式,1.12後,不管在$GOPATH/src裏仍是在外面,都會使用go.mod 裏 require的包
  • off 關閉模式,就是老規矩。

問題三: 依賴包中的地址失效了怎麼辦?好比 golang.org/x/… 下的包都沒法下載怎麼辦?

在go快速發展的過程當中,有一些依賴包地址變動了。
之前的作法

  1. 修改源碼,用新路徑替換import的地址
  2. git clone 或 go get 新包後,copy到$GOPATH/src裏舊的路徑下

不管什麼方法,都不便於維護,特別是多人協同開發時。

使用go.mod就簡單了,在go.mod文件裏用 replace 替換包,例如

replace golang.org/x/text => github.com/golang/text latest

這樣,go會用 github.com/golang/text 替代golang.org/x/text,原理就是下載github.com/golang/text 的最新版本到 $GOPATH/pkg/mod/golang.org/x/text下。

問題四: init生成的go.mod的模塊名稱有什麼用?

本例裏,用 go mod init hello 生成的go.mod文件裏的第一行會申明
module hello

由於咱們的項目已經不在$GOPATH/src裏了,那麼引用本身怎麼辦?就用模塊名+路徑。

例如,在項目下新建目錄 utils,建立一個tools.go文件:

package utils

import 「fmt」

func PrintText(text string) {
    fmt.Println(text)
}

在根目錄下的hello.go文件就能夠 import 「hello/utils」 引用utils

package main

import (
"hello/utils"

"github.com/astaxie/beego"
)

func main() {

    utils.PrintText("Hi")

    beego.Run()
}

問題五:之前老項目如何用新的包管理

  1. 若是用auto模式,把項目移動到$GOPATH/src
  2. 進入目錄,運行 go mod init + 模塊名稱
  3. go build 或者 go run 一次

關於Go 1.12的包管理介紹大體就到此了

根據官方的說法,從Go 1.13開始,模塊管理模式將是Go語言開發的默認模式。

因此,Pick起來吧!

有問題或者須要討論的朋友,能夠給我留言,共同窗習,一塊兒進步

曉代碼公衆號

相關文章
相關標籤/搜索