<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          第一個Go語言類庫:啟用、創(chuàng)建并發(fā)布第一個模塊

          共 5771字,需瀏覽 12分鐘

           ·

          2021-01-25 16:43

          這是《Go語言簡易入門》系列內(nèi)容第6篇,所有內(nèi)容列表見:https://yishulun.com/books/go-easy/目錄.html。所有源碼及資料在“程序員LIYI”公號回復(fù)“Go語言簡易入門”獲取。

          模塊化是編程界的潮流,無論是前端Vue、微信小程序開發(fā),還是后端Node.js、Golang開發(fā),都講究模塊化。模塊化的本質(zhì)是分工協(xié)作,將功能相對獨立完善的代碼以模塊方式發(fā)布,以便在其它程序中復(fù)用,這與汽車廠分別制造發(fā)動機、輪胎、車門等零件,然后再組裝是一個道理。

          GO111MODULE的由來

          那么在Go語言開發(fā)中,如何進行模塊化開發(fā)呢?

          默認(rèn)在官方教程《如何使用Go編程》中是不講這一塊的,環(huán)境變量GO111MODULE默認(rèn)是關(guān)閉的,運行官方示例也不會受到影響。但模塊化確實是非常重要的概念,是任何想認(rèn)真使用這門語言的開發(fā)者都避不開的。

          上面我們提到了GO111MODULE,什么是GO111MODULE?

          這個名稱中有三個數(shù)字一,不是字母“l(fā)”,是數(shù)字“1”,它表示在Go語言1.11版本中加入的環(huán)境變量。單從這個名稱來看,它很有可能被干掉,但事實上一真沒有。

          在以前最早2009年Go語言發(fā)布的時候,源碼都是通過GOPATH管理的。怎么理解呢?在代碼中我們通過import關(guān)鍵字引入一個第三方類庫,Go程序會依次向GOPATH、GOROOT這兩個總目錄下去查找,哪個先查到,就用哪個。

          但是我們知道,位于github上的類庫,master分支是最新源碼,這個源碼經(jīng)常變動,有時候我們使用的僅是歷史上的某個版本。有的開發(fā)者注意到了這一點,所以當(dāng)類庫重構(gòu)的時候,會將舊代碼打一個Release版本,這樣即使源碼修改了,只要我們找到歷史版本,也不影響我們程序的正常運行。

          但是問題起來,有的程序需要用某個類庫的新版本,有的需要用舊版本,GOPATH只有一個,怎么處理這個矛盾呢?

          那個時候我用的是最笨的方法,起新項目的時候,我將GOPATH目錄復(fù)制一份,并修改GOPATH變量為復(fù)制后的新目錄。一個項目對應(yīng)一個GOPATH,這樣不同項目的類庫版本就不會相互掣肘了。

          可能不止我一個人這么使用。Go語言在1.5版本的時候,推出了一個vendor特征,它充許我們將當(dāng)前項目所用的所有第三方類庫,全部自動拷貝到一個叫做vendor的子目錄下。Go程序在編譯的時候,會首先向vendor目錄查找,如果沒找到,再向GOPATH、GOROOT目錄查找。

          但是這種方式并沒有從根本上在Go語言中解決模塊化編程的問題,項目在共享和分發(fā)時,隨身攜帶許多第三方類庫的源碼,既占空間,又不利于統(tǒng)一升級類庫。如果第三方類庫在新版本中修復(fù)了一個bug,而我們需要更新,在多個項目中更新將是一件麻煩事。

          后來,在Go語言1.11版本中,Go語言推出了GO111MODULE環(huán)境變量,及mod子指令,基于這個變量和子指令,可以完美模塊化編程了。接下來我們看看,一般是怎么做的。

          創(chuàng)建并發(fā)布自己的第一個模塊

          首先我們在GOPATH路徑外面創(chuàng)建一個目錄:

          rixingyike/
          first
          main.go
          str
          reserve.go

          這是兩個示例。first目錄是測試代碼,用于測試我們發(fā)布的模塊。str是我們準(zhǔn)備創(chuàng)建和發(fā)布的模塊。模塊位于多級目錄下,這是我們故意為之的。go語言的類包都是單名一級引入,但在實際的項目開發(fā)中,我們的模塊往往處于多級目錄下,我們看看這種情況一般是怎么處理的。

          先看一下模塊str/reserve.go的源碼:

          // go-easy/rixingyike/str/reserve.go
          package str

          import(
          "fmt"
          "github.com/kataras/iris/v12"
          )

          // Reverse 將其實參字符串以符文為單位左右反轉(zhuǎn)
          func Reverse(s string) string {
          r := []rune(s)
          for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
          r[i], r[j] = r[j], r[i]
          }
          fmt.Println(string(r))
          return string(r)
          }

          // StartServer ...
          func StartServer() {
          app := iris.New()
          app.Handle("GET", "/user/{id:uint64}", func(ctx iris.Context) {
          id, _ := ctx.Params().GetUint64("id")
          ctx.JSON(id)
          })
          app.Listen(":8080")
          }

          我們在這個文件中引入了iris框架。我們需要在這個模塊中啟用go mod,執(zhí)行如下指令:

          cd go-easy/rixingyike/str/
          go mod init gitee.com/rxyk/go-easy/rixingyike/str

          go mod指令后面是我們模塊的名稱,注意這里分部分,前面gitee.com/rxyk/go-easy是我們的倉庫地址,后面/rixingyike/str是倉庫中模塊的相對路徑。

          這里有一個問題值得注意下,就是我們的module name是gitee.com/rxyk/go-easy/rixingyike/str,但是reserve.go文件中的package名稱卻是str,后者是引入以后在源碼中使用的單名,這兩個名稱是不需要也不能一致的。

          接下來是關(guān)鍵,接著執(zhí)行指令:

          go env -w GOPRIVATE="gitee.com"
          git tag rixingyike/str/v1.0.0
          git push origin rixingyike/str/v1.0.0

          第一行指令,是將gitee.com這個域名添加進GOPRIVATE變量中,GOPRIVATE這個變量的值可以用逗號分隔添加多個值,但這里我們不需要添加多個。這一步的環(huán)境變量設(shè)置,是為了跳過對gitee.com域名的網(wǎng)絡(luò)代理。這是國內(nèi)網(wǎng)站,是不需要代理的。

          第二行和第三行指令是創(chuàng)建一個新的tag,并提交到遠(yuǎn)端倉庫里。這里的關(guān)鍵是tag名,前面rixingyike/str/是模塊在倉庫中的相對路徑,后面v1.0.0才是模塊的版本號。默認(rèn)情況下,如果類庫在根目錄下是不需要這樣處理的,直接寫一個像v1.0.0這樣的版本號就可以了。

          使用自己的第一個模塊并在本地調(diào)試

          現(xiàn)在模塊已經(jīng)在線上發(fā)布了,接下來我們看一下怎么使用。

          現(xiàn)在我們切換到first例目錄,并進行module初始化,執(zhí)行如下指令:

          cd go-easy/rixingyike/first/
          go mod init gitee.com/rxyk/go-easy/rixingyike/first
          vim main.go ...
          go get gitee.com/rxyk/go-easy/rixingyike/[email protected]

          第二行指令中這個module的名稱,因為不需要對外發(fā)布,其實是無所謂的。接下來編輯main.go的源碼:

          // go-easy/rixingyike/first/main.go
          package main

          import (
          "fmt"
          "gitee.com/rxyk/go-easy/rixingyike/str"
          "github.com/nleeper/goment"
          )

          func main() {
          fmt.Printf("%s\n",str.Reverse("hi,ly"))
          var g,_ = goment.New("2021-01-23 09:30:26")
          println(g.ToString())
          str.StartServer()
          }

          在這個測試示例中,我們引入了goment和str這兩個模塊,其中后者是我們自己定義的。

          我們看一下自動生成的go mod文件:

          // go-easy/rixingyike/first/go.mod
          module gitee.com/rxyk/go-easy/rixingyike/first
          go 1.15
          // replace gitee.com/rxyk/go-easy/rixingyike/str v1.0.0 => ../str
          require (
          gitee.com/rxyk/go-easy/rixingyike/str v1.0.0
          github.com/nleeper/goment v1.4.0
          )

          輸出是這樣的:

          yl,ih
          yl,ih
          2021-01-23 09:30:26 +0000 UTC
          Now listening on: http://localhost:8080
          Application started. Press CMD+C to shut down.

          在這個文件中,第三行代碼replace,是將依賴包替換。有兩個作用:

          • 如果某個類庫因為網(wǎng)絡(luò)原因,不能下載,可以用這個功能

          • 我們自己開發(fā)的模塊,需要在本地調(diào)試

          我們將這行配置反注釋一下,而main.go中的import引入代碼不需要修改,再運行代碼,調(diào)用的就是本地的str下的代碼了。這個設(shè)置,方便我們在本地進行模塊代碼,調(diào)試完成后再統(tǒng)一上傳。

          關(guān)于模塊化編程,以上就是全部內(nèi)部了。接下來我們補充了解一些相關(guān)的概念。

          如何臨時修改GO111MODULE變量?

          有時候我們需要臨時修改這個變量的值,但并不需要永久修改。有兩個方法:

          go env -w GO111MODULE=on
          export GO111MODULE=on

          這是兩種方式,以第二種效果最佳。第一種方式go env -w *是一種Go語言提供的通用的編輯環(huán)境變量的方式。

          開啟go mod后,還能再使用vendor統(tǒng)一打包源碼嗎?

          可以的,在項目模塊目錄下,例如str,執(zhí)行:

          go mod vendor

          這樣就會在str目錄下生成一個vendor子目錄,它里面有所有的依賴包。

          GO111MODULE有哪些有效值?

          有三個值:

          • GO111MODULE=off,不支持module功能,此時查找依賴包的次序是:vendor、GOPATH、GOROOT。

          • GO111MODULE=on,支持使用modules,會從vendor目錄下查找,但不會去GOPATH、GOROOT目錄下查。

          • GO111MODULE=auto,是默認(rèn)值,自動性取決于上下文目錄。$GOPATH/src之中的項目繼續(xù)使用GOPATH模式;$GOPATH/src之外的項目使用模塊化模式。

          go mod指令,除init外,還有哪些子指令?

          相關(guān)指令:

          • download download modules to local cache (下載依賴的module到本地cache))

          • edit edit go.mod from tools or scripts (編輯go.mod文件)

          • graph print module requirement graph (打印模塊依賴圖))

          • init initialize new module in current directory (在當(dāng)前文件夾下初始化一個新的module, 創(chuàng)建go.mod文件))

          • tidy add missing and remove unused modules (增加丟失的module,去掉未使用的module)

          • vendor make vendored copy of dependencies (將依賴復(fù)制到vendor下)

          • verify verify dependencies have expected content (校驗依賴)

          • why explain why packages or modules are needed (解釋為什么需要依賴)

          最常使用的子指令是init、download、tidy和vendor。

          啟用go mod后,如何查詢和安裝指定版本的依賴包?

          和原來是一樣的。可以使用:

          go get github.com/kataras/iris/v12@latest

          @符號后面是版本號,latest代表最新。這個版本就是git網(wǎng)站上的發(fā)行版標(biāo)簽。可以用如下指令查詢所有可用標(biāo)簽名:

          go list -m -versions github.com/kataras/iris/v12

          輸出:

          v12.0.0 v12.0.1 v12.1.0 v12.1.1 v12.1.2 v12.1.3 v12.1.4 v12.1.5 v12.1.6 v12.1.7 v12.1.8 v12.2.0-alpha v12.2.0-alpha2

          其中地址中的v12是什么?它是該倉庫的一個分支。它還有另一個分支:v0.0.1。

          引入國外的一些類庫,如何設(shè)置代理?

          使用GOPROXY變量。我的設(shè)置是這樣的:

          export GOPROXY="https://goproxy.io,https://mirrors.aliyun.com/goproxy/,https://goproxy.cn,direct"

          三個網(wǎng)站的說明是這樣的:

          • https://goproxy.io?最早的Go模塊鏡像代理網(wǎng)站

          • https://mirrors.aliyun.com/goproxy/?阿里鏡像代理網(wǎng)站

          • https://goproxy.cn?七牛云贊助支持的代理網(wǎng)站 |

          以逗號分隔。最后的direct代表到源地址下載。

          我講明白沒有,歡迎留言討論。

          2021年1月23日


          本文寫作中參考了以下鏈接,一并致謝:

          • https://blog.csdn.net/yptsqc/article/details/105270530

          • https://morven.life/notes/the_go_language/

          • https://github.com/goproxy/goproxy.cn/issues/9

          瀏覽 70
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷婷五月天AV | 91丨九色丨国产在线 | 特色黄片网站 | 亚洲精品一二三四区 | 国产色黄网站 |