1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        第一個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”公號回復“Go語言簡易入門”獲取。

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

        GO111MODULE的由來

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

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

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

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

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

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

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

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

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

        但是這種方式并沒有從根本上在Go語言中解決模塊化編程的問題,項目在共享和分發(fā)時,隨身攜帶許多第三方類庫的源碼,既占空間,又不利于統(tǒng)一升級類庫。如果第三方類庫在新版本中修復了一個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是我們準備創(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,后者是引入以后在源碼中使用的單名,這兩個名稱是不需要也不能一致的。

        接下來是關鍵,接著執(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)境變量設置,是為了跳過對gitee.com域名的網(wǎng)絡代理。這是國內(nèi)網(wǎng)站,是不需要代理的。

        第二行和第三行指令是創(chuàng)建一個新的tag,并提交到遠端倉庫里。這里的關鍵是tag名,前面rixingyike/str/是模塊在倉庫中的相對路徑,后面v1.0.0才是模塊的版本號。默認情況下,如果類庫在根目錄下是不需要這樣處理的,直接寫一個像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)絡原因,不能下載,可以用這個功能

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

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

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

        如何臨時修改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,是默認值,自動性取決于上下文目錄。$GOPATH/src之中的項目繼續(xù)使用GOPATH模式;$GOPATH/src之外的項目使用模塊化模式。

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

        相關指令:

        • 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 (在當前文件夾下初始化一個新的module, 創(chuàng)建go.mod文件))

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

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

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

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

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

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

        和原來是一樣的??梢允褂茫?/p>

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

        @符號后面是版本號,latest代表最新。這個版本就是git網(wǎng)站上的發(fā)行版標簽??梢杂萌缦轮噶畈樵兯锌捎脴撕灻?/p>

        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。

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

        使用GOPROXY變量。我的設置是這樣的:

        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
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩最新高清无码 | 中国乱伦一级大黄片 | 少妇bbb撒尿做饭爱bbw | 伊人激情五月 | 久热精品免费 | 女人被添荫蒂舒服极了一 | 全肉乱妇杂乱小说txt | 张柏芝54张无删码艳照在线播放 | 孟若羽一级婬片A片 | 国产啊灬啊灬啊灬快好深视频 |