zoukankan      html  css  js  c++  java
  • Go Module

    1.什么是Go Module?

    简而言之,Go Modul是Go在1.12之后官方发布的包管理工具。

    现代的语言都有很多好用的包管理工具,如 pip 之于 python,gem 之于 ruby,npm 之于 nodejs。然而 Golang 早期版本却没有官方的包管理器,直到 go1.5 才添加了实验性的 vendor。尽管官方的不作为(保守),还是无法阻止社区的繁荣。社区诞生了许多工具,比较有代表如 govender,glide,gopm,以及半官方的 dep 等。

    2.Go Module带来的改变–淡化了GOPATH

    在 go1.12 之前,安装 golang 之后,需要配置两个环境变量即GOROOT 和GOPATH。前者是 go 安装后的所在的路径,后者是开发中自己配置的,用于存放go 源代码的地方。在 GOPATH 路径内,有三个文件夹,分别是

    • bin: go 编译后的可执行文件所在的文件夹
    • pkg: 编译非 main 包的中间连接文件
    • src: go 项目源代码

    开发的程序源码则放在src里,可以在src里创建多个项目。每一个项目同时也是一个文件夹。

    1.12之后,不需要人工配置,系统会以

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    ~/go
    2
    1
     
     

    目录为默认GOPATH,可以简单理解为Maven的.m2目录。

    3.关于package

    golang 的所有文件都需要指定其所在的包(package),包有两种类型,一种是 main 包,使用 package main 在代码的最前面声明。另外一种就是 非main 包,使用 package + 包名 。main 包的可以有唯一的一个 main 函数,这个函数也是程序的入口。也只有 main 包可以编译成可执行的文件。 注意:若一目录中有下一级目录,可以认为是一个内嵌的包,这个包与当前包即使包名相同也不是一个包!包名的完整路径是从项目。如

     
     
     
    xxxxxxxxxx
    12
     
     
     
     
    1
    ➜  ~ tree go-mod-test
    2
    go-mod-test
    3
    ├── go.mod
    4
    └── src
    5
        ├── main.go
    6
        └── pk1
    7
            ├── pk1
    8
            │   └── pk1.go
    9
            └── pk1.go
    10
    11
    3 directories, 4 files
    12
    1234567891011
     
     

    src中有个pk1包,pk1包里面有个嵌入的pk1包。三个go文件如下:

     
     
     
    xxxxxxxxxx
    33
     
     
     
     
    1
    //pk1/pk1.go
    2
    package pk1
    3
    4
    import "fmt"
    5
    6
    func Pk1Func()  {
    7
    fmt.Println("pk1.Pk1Func")
    8
    9
    }
    10
    123456789
    11
    //pk1/pk1/pk1.go
    12
    package pk1
    13
    14
    import "fmt"
    15
    16
    func Pk1Func()  {
    17
    fmt.Println("pk1.pk1.Pk1Func")
    18
    19
    }
    20
    123456789
    21
    package main
    22
    23
    import (
    24
    "go-mod-test/src/pk1"
    25
    pk1pk1 "go-mod-test/src/pk1/pk1"
    26
    )
    27
    28
    func main() {
    29
    pk1.Pk1Func()
    30
    pk1pk1.Pk1Func()
    31
    32
    }
    33
    123456789101112
     
     

    注意:main.go在调用是两个pk1都用了全路径,由于连个包名字都是pk1,main在导入是冲突需要引入别名pk1pk1。

    4.关于Module

    原理就不赘述,大家留心main.go引入pk1用的

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    go-mod-test/src/pk1
    2
    1
     
     

    注意前面的『“go-mod-test”』这个准确说是当前项目的父Module。在项目路径里通过执行

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    go mod init go-mod-test
    2
    1
     
     

    来生成go.mod,即初始化Module,内容就两行,模块名及go版本。

     
     
     
    xxxxxxxxxx
    5
     
     
     
     
    1
    ➜  go-mod-test cat go.mod
    2
    module go-mod-test
    3
    4
    go 1.14
    5
    1234
     
     

    此时我们在main.go加入依赖,如

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
     _ "github.com/gin-gonic/gin"
    2
    1
     
     

    然后我们运行

     
     
     
    xxxxxxxxxx
    4
     
     
     
     
    1
    ➜  go-mod-test go mod tidy
    2
    go: finding module for package github.com/gin-gonic/gin
    3
    go: found github.com/gin-gonic/gin in github.com/gin-gonic/gin v1.6.2
    4
    123
     
     

    就是同该命令来更新依赖,添加需要的,移除多余的,更新结果保存在go.mod以及go.sum。

    go.mod可以加入版本管理,go.sum不建议,避免跨平台校验可能出错,而且执行go mod tidy可以自动生成。

     
     
     
    xxxxxxxxxx
    11
     
     
     
     
    1
    ➜  go-mod-test tree .
    2
    .
    3
    ├── go.mod
    4
    ├── go.sum
    5
    └── src
    6
        ├── main.go
    7
        └── pk1
    8
            ├── pk1
    9
            │   └── pk1.go
    10
            └── pk1.go
    11
    12345678910
     
     

    go.mod文件比初始化后多了一行依赖记录,版本号是自动更新的,也可以手动修改该文件指定版本号。

     
     
     
    xxxxxxxxxx
    7
     
     
     
     
    1
    ➜  go-mod-test cat go.mod
    2
    module go-mod-test
    3
    4
    go 1.14
    5
    6
    require github.com/gin-gonic/gin v1.6.2
    7
    123456
     
     

    go.sum保存了依赖的传递以及其版本号、hash值

     
     
     
    xxxxxxxxxx
    9
     
     
     
     
    1
    ➜  go-mod-test cat go.sum
    2
    github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
    3
    github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
    4
    github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
    5
    ...省略N行...
    6
    h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
    7
    gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
    8
    gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
    9
    12345678
     
     

    到目前为止,我们用了两条命令,即

     
     
     
    xxxxxxxxxx
    3
     
     
     
     
    1
    go mod init module-name
    2
    go mod tidy
    3
    12
     
     

    下面看看go mod 有哪些功能

     
     
     
    xxxxxxxxxx
    25
     
     
     
     
    1
    ➜  go-mod-test go mod help
    2
    Go mod provides access to operations on modules.
    3
    4
    Note that support for modules is built into all the go commands,
    5
    not just 'go mod'. For example, day-to-day adding, removing, upgrading,
    6
    and downgrading of dependencies should be done using 'go get'.
    7
    See 'go help modules' for an overview of module functionality.
    8
    9
    Usage:
    10
    11
    go mod <command> [arguments]
    12
    13
    The commands are:
    14
    15
    download    download modules to local cache
    16
    edit        edit go.mod from tools or scripts
    17
    graph       print module requirement graph
    18
    init        initialize new module in current directory
    19
    tidy        add missing and remove unused modules
    20
    vendor      make vendored copy of dependencies
    21
    verify      verify dependencies have expected content
    22
    why         explain why packages or modules are needed
    23
    24
    Use "go help mod <command>" for more information about a command.
    25
    123456789101112131415161718192021222324
     
     

    原来命令也不多,除了刚才的两个另外关注

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    go mod download
    2
    1
     
     

    看名字指定是下载依赖到本地缓存,那本地保存在哪呢?我们想起了前面说到的默认GOPATH

     
     
     
    xxxxxxxxxx
    31
     
     
     
     
    1
    ➜  ~ tree $GOPATH -L 4
    2
    /Users/alexhu/go
    3
    └── pkg
    4
        ├── mod
    5
        │   ├── cache
    6
        │   │   └── download
    7
        │   ├── github.com
    8
        │   │   ├── davecgh
    9
        │   │   ├── gin-contrib
    10
        │   │   ├── gin-gonic
    11
        │   │   ├── go-playground
    12
        │   │   ├── golang
    13
        │   │   ├── google
    14
        │   │   ├── json-iterator
    15
        │   │   ├── leodido
    16
        │   │   ├── mattn
    17
        │   │   ├── modern-go
    18
        │   │   ├── pmezard
    19
        │   │   ├── stretchr
    20
        │   │   └── ugorji
    21
        │   ├── golang.org
    22
        │   │   └── x
    23
        │   └── gopkg.in
    24
        │       ├── check.v1@v0.0.0-20161208181325-20d25e280405
    25
        │       └── yaml.v2@v2.2.8
    26
        └── sumdb
    27
            └── sum.golang.org
    28
                └── latest
    29
    30
    25 directories, 1 file
    31
    123456789101112131415161718192021222324252627282930
     
     

    果然,都下载到了$GOPATH/pkg/mod目录下了!其它命令试试就知道了!这里提醒下

     
     
     
    xxxxxxxxxx
    3
     
     
     
     
    1
    go mod vendor
    2
    3
    12
     
     

    会在项目中建立vendor目录,将依赖下载在该目录中,目录结构类似前面说的的pkg/mod目录,整个项目打包的话方便没有网络也可以编译项目。一般情况下不要提交本目录到版本管理中。

    6.编译项目

    根据老习惯,建立个bin目录,用下面命令生产可执行文件,文件名默认同源文件名:

     
     
     
    xxxxxxxxxx
    6
     
     
     
     
    1
    ➜  go-mod-test mkdir .bin
    2
    ➜  go-mod-test go build -o ./bin/ ./src/main.go
    3
    ➜  go-mod-test ./bin/main
    4
    pk1.Pk1Func
    5
    pk1.pk1.Pk1Func
    6
    12345
     
     

    另外,我们将main.go源文件放到项目目录下,然后执行

     
     
     
    xxxxxxxxxx
    3
     
     
     
     
    1
    ➜  go-mod-test cp src/main.go .
    2
    ➜  go-mod-test  go build -o ./bin/ 
    3
    12
     
     

    这时发现bin中生产的可执行文件不是main而是包名go-mod-test!

    7.Go Moudle被墙相关

    7.1下载失败

    go mod download下载失败包库,增加代理,在.bashr或.zshrc中增加如下export

     
     
     
    xxxxxxxxxx
    3
     
     
     
     
    1
    export GO111MODULE=on
    2
    export GOPROXY=https://goproxy.io
    3
    12
     
     

    https://goproxy.io若不稳定可以用七牛的https://goproxy.cn,或网上搜下其它的代理服务器。

    7.2校验失败

    如果在运行go mod download,提示Get https://sum.golang.org/lookup/xxxxxx: dial tcp 216.58.200.49:443: i/o timeout,则是因为Go 设置了默认的GOSUMDB=sum.golang.org,这个网站是被墙了的,用于验证包的有效性,可以通过如下命令关闭:

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    go env -w GOSUMDB=off
    2
    1
     
     

    但不建议,建议的做法是设置 GOSUMDB=“sum.golang.google.cn”,这个是专门为国内提供的sum 验证服务

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    go env -w GOSUMDB="sum.golang.google.cn"
    2
    1
     
     
    7.3 Goland中设置

    系统的GOPROXY在Goland中会覆盖,所以Goland中要重新设置:

     
     
     
    xxxxxxxxxx
    2
     
     
     
     
    1
    File-->Preferences-->Go-->Go Modules(vgo)-->Enable Go Modules(vgo) intergration-->proxy-->https://goproxy.cn,direct
    2
    1
     
     

    即可。

    8.项目组织

    先看下重构后的本Demo项目结构

     
     
     
    xxxxxxxxxx
    25
     
     
     
     
    1
    ➜  go-mod-test tree
    2
    .
    3
    ├── Makefile
    4
    ├── bin
    5
    │   ├── main
    6
    │   ├── submain1
    7
    │   └── submain2
    8
    ├── go.mod
    9
    ├── go.sum
    10
    └── src
    11
        ├── main
    12
        │   └── demomain.go
    13
        ├── pk1
    14
        │   ├── pk1
    15
        │   │   ├── pk1.go
    16
        │   │   └── pk1_test.go
    17
        │   ├── pk1.go
    18
        │   └── pk1_test.go
    19
        ├── submain1
    20
        │   └── submain1-main.go
    21
        └── submain2
    22
            └── submain2-main.go
    23
    24
    7 directories, 13 files
    25
    123456789101112131415161718192021222324
     
     

    说明如下: 1.项目根目录下有模块信息,即go.mod。 2.main目录(包)为主模块,需要编译成可执行文件。 3.pk1及其子目录pk1可以理解为公共目录,如放项目的一下公共源文件,不编译成可执行文件。 4.submain1及submain2为子模块(如功能微服务),需要编译成可执行文件,可能引用公共模块里的单元文件。 5.xxx_test.go为测试文件,命名规则就是单元名加后缀_test。 6.Makefile,与make工具搭档是构建系统的鼻祖,简化构建。如本例中

     
     
     
    xxxxxxxxxx
    14
     
     
     
     
    1
    ➜  go-mod-test make build
    2
    go build -o ./bin/  ./src/main/...
    3
    ./bin/main
    4
    2020/03/30 17:46:15 hahahaha
    5
    2020/03/30 17:46:15 pk1.pk1.Pk1Func
    6
    go build -o ./bin/ ./src/submain1/...
    7
    ./bin/submain1
    8
    2020/03/30 17:46:16 submain1.main()
    9
    2020/03/30 17:46:16  msg from pk1/Pk1Func(): haha
    10
    go build -o ./bin/ ./src/submain2/...
    11
    ./bin/submain2
    12
    2020/03/30 17:46:16 submain2.main()
    13
    2020/03/30 17:46:16 msg from pk1/pk1/Pk1Func()): pk1.pk1.Pk1Func
    14
    12345678910111213
     
     

    一个make build帮我们编译好了并执行了三个(子)项目。再如

     
     
     
    xxxxxxxxxx
    33
     
     
     
     
    1
    ➜  go-mod-test make test
    2
    go test  ./src/... -v
    3
    ?   go-mod-test/src/main[no test files]
    4
    === RUN   TestPk1Func
    5
    === RUN   TestPk1Func/msg
    6
    === RUN   TestPk1Func/ha
    7
    --- PASS: TestPk1Func (0.00s)
    8
        --- PASS: TestPk1Func/msg (0.00s)
    9
        --- PASS: TestPk1Func/ha (0.00s)
    10
    === RUN   TestAdd
    11
    === RUN   TestAdd/1+2
    12
    --- PASS: TestAdd (0.00s)
    13
        --- PASS: TestAdd/1+2 (0.00s)
    14
    PASS
    15
    ok  go-mod-test/src/pk1(cached)
    16
    === RUN   TestPk1Func
    17
    === RUN   TestPk1Func/default
    18
    --- PASS: TestPk1Func (0.00s)
    19
        --- PASS: TestPk1Func/default (0.00s)
    20
    === RUN   TestSub
    21
    === RUN   TestSub/5-3
    22
    === RUN   TestSub/4-2
    23
        TestSub/4-2: pk1_test.go:40: Sub() = 2, want 1
    24
    --- FAIL: TestSub (0.00s)
    25
        --- PASS: TestSub/5-3 (0.00s)
    26
        --- FAIL: TestSub/4-2 (0.00s)
    27
    FAIL
    28
    FAILgo-mod-test/src/pk1/pk10.204s
    29
    ?   go-mod-test/src/submain1[no test files]
    30
    ?   go-mod-test/src/submain2[no test files]
    31
    FAIL
    32
    make: *** [test] Error 1
    33
    1234567891011121314151617181920212223242526272829303132
     
     

    跑完了全部单元测试。 本文结束。

    转:https://blog.csdn.net/dgatiger/article/details/105205190

  • 相关阅读:
    Netty 源码解读(二)-ChannelPipeline、ChannelHandler、ChannelHandlerContext
    Netty源码解读(一)-服务启动和接收请求源码
    浅谈自动化测试框架开发
    程序运行时环境
    常见的Linux内核线程
    一个好用gdb扩展工具
    使用Qemu模拟Numa机器
    使用qemu的nat方式登录
    2021.32 量化
    2021.31 模型
  • 原文地址:https://www.cnblogs.com/yzg-14/p/14253934.html
Copyright © 2011-2022 走看看