go包管理和go mod(35)

2023年 7月 15日 77.2k 0

在go中包是一个代码的组织方式,代码最后的分发都是以包的方式分发的。包也是go中最小的分发单位。包也是函数和数据的集合,将相关特性的函数和数据放在同一的文件/目录进行管理,每个包都可以作为独立的单元维护并提供给其他项目进行使用。通常,包中存放的就是变量,函数,产量,结构体等等。请输入图片描述go源文件都需要在开头使用package声明所在包,包名告知编译器那些是包的源代码用于编译库文件,其次包名用于限制包内成员对外的可见性,最后包用于在包外对公开成员的访问。

1.包

包名使用简短的小写字母,常与所在目录名保持一致,一个包中可以由多个Go源文件组成,通常,使用相同包名。

  • go env

我们可以使用go env查看go环境中的gopath

[root@linuxea.com /opt/Golang]# go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/root/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build982029746=/tmp/go-build -gno-record-gcc-switches"

在windows上也可也使用go env

  • 可以通过set GOPATH=C:UsersMarkgo;E:golangNodeproject9296day来添加

2.包导入-path

  • 绝对路径导入

在gopath目录中查找包。如:

import (
    "fmt"
    "gpkgname/pkg01"
)
  • 相对路径导入

在当前文件所在目录查找,如:

import "./gpkgname/pkg02"
  • 点导入

在调用点导入包中的成员时可以直接使用成员名称进行调用(省略包名)

import . "fmt"

. 简导入,在导入前加入点,这种并不推荐使用

  • 别名导入

当导入不同路径的相同包名时,可以别名导入为包重命名,避免冲突

import ff "fmt"

fmt在调用的时候就成了ff

  • 下划线导入

go不允许包导入后不使用,在某些情况下需要初始化包,使用空白符作为别名进行导入,从而使得包中的初始化函数可以执行。

_ 空白标识符通常和初始化函数init一起使用,在init函数中,不管是以什么方式导入,都会执行包的初始化函数。空白标识符仅仅用作调用初始化函数。

3.包的成员可见性

go语言使用名称首字母大小写来判断对象(常量,变量,函数,类型,结构体,方法等)的访问权限,首字母大写标识包外可见(公开的),否则仅包内可访问(内部的)。比如变量:

var Name string // 包外可见
var NAME string // 包外可见
var NaMe string // 包外可见

var nAme string    // 包外不可见
var naME string    // 包外不可见
var nAME string    // 包外不可见

其他常量,变量,函数,类型,结构体,方法也是需要首字母大写才能被包外可见。

4.main包和init函数

  • main包

main包用于声明告知编译器将包编译为二进制可执行文件。在main包中的main函数是程序的入口,无返回值,无参数。在一个main包中只有一个main函数

  • 5.init函数

init函数是初始化包使用,无返回值,无参数,每个包中建议只定义一个,init函数在import包时自动被调用

如果有函数,通常init会先执行

[root@linuxea.com /opt/Golang/work4]# cat init.go
package main
import "fmt"
func main(){
    fmt.Println("main")
}
func init(){
    fmt.Println("init")
}

运行

[root@linuxea.com /opt/Golang/work4]# go run init.go
init
main

5.go包管理-vendor

  • vendor目录

在1.5之前只有gopath方式,需要将代码放置gopath目录,而vendor机制是将项目依赖包拷贝到到vendor目录,在编译时使用项目下的vendor目录中的包进行编译

这种方式解决 了依赖外包包过多的问题,而且通过go get下载的库会放在第一个目录中,并且在多项目中,如果不向前兼容就容易造成复杂的库依赖等问题,同时系统的目录就会越来越大。

通常包搜索会在当前包下的vendor目录查找,向上级目录查找,直到GOPATH/src/vendor目录,而后在GOPATH目录查找,最后在GOROOT目录查找

第三方包,可以通过go get工具下载和安装第三方包以及依赖,需要安装与第三方包匹配的代码管理工具,比如git,svn等。如果二进制的包会放在bin目录,如果是库文件会放在pkg目录下。

go get会判断本地是否有,如果有就不进行下载,我们需要配合参数进行使用。

常用参数:

  • -d : 仅下载依赖包
  • -u: 更新包并安装
  • -x: 打印执行的命令
  • -v: 打印构建的包
  • -insecure: 允许使用http协议下载包

可以通过go help get查看帮助信息。

6.go包管理-modules机制

相对于上面的gopath,modules不用设置GOPATH,代码可以放在任何位置,当你运行的时候会自动下载依赖管理。并且可以做版本控制,而在go get的时候默认是使用最新的版本,但是在go modules中,可以指定版本号。

在go module中也不允许相对导入。也可以使用replace来做一些错误修复。

go modules机制的包管理,同时保留GOPATH和Vendor机制,使用临时的环境变量GO111MODULE进行控制,GO111MODULE有三个可选值

a). 当off时,构建项目是在GOPATH和Vendor目录搜索目标程序依赖包

b). 当on时,构建项目则始终使用Go modules机制,在GOPATH/pkg/mod目录搜索目标程序依赖包

c). 当auto时,默认为auto,当构建代码不再GOPATH/src的子目录且包含go.mod文件,则使用Go.modules机制,否则使用GOPATH和vendor机制。

6.1 go module初始化

运行go mod init modname,比如初始化test

假如初始化的是一个github项目地址,就需要写完整,如:

go mod init github.com/marksugar/gotest

[root@linuxea.com /opt/Golang/work4]# mkdir test
[root@linuxea.com /opt/Golang/work4]# go mod init test
go: creating new go.mod: module test
[root@linuxea.com /opt/Golang/work4]# ll 
total 8
-rw------- 1 root root 21 Sep 29 21:46 go.mod
-rw-r--r-- 1 root root 98 Sep 29 19:02 init.go
drwxr-xr-x 2 root root  6 Sep 29 21:45 test

执行完成后,就会产生一个go.mod。在这个文件中会有go的版本信息和模块名称

[root@linuxea.com /opt/Golang/work4]# cat go.mod 
module test

go 1.12

6.2go buld

当执行go buid的时候会自动下载。

  • 示例

比如写一段简单的代码,使用beego

代码要放在模块中,目录结构如下:

[root@linuxea.com /opt/Golang/work4]# tree ./
./
├── go.mod
├── go.sum
├── main.go
└── test

0 directories, 4 files
[root@linuxea.com /opt/Golang/work4]# cat main.go 
package main
import (
    "github.com/astaxie/beego"
)
func main(){
    beego.Run()
}

而后使用go build就不会自动下载依赖

[root@linuxea.com /opt/Golang/work4]# go build
go: finding github.com/astaxie/beego v1.12.0
go: downloading github.com/astaxie/beego v1.12.0
go: extracting github.com/astaxie/beego v1.12.0
go: finding github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76
go: finding github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542
go: finding github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c
go: finding github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712
go: finding github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb
go: finding github.com/pelletier/go-toml v1.2.0
go: finding github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58
go: finding github.com/lib/pq v1.0.0
go: finding github.com/elazarl/go-bindata-assetfs v1.0.0
go: finding github.com/casbin/casbin v1.7.0
go: finding github.com/go-redis/redis v6.14.2+incompatible
go: finding github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726
go: finding github.com/mattn/go-sqlite3 v1.10.0
go: finding github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a
go: finding github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
go: finding github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737
go: finding github.com/gogo/protobuf v1.1.1
go: finding golang.org/x/net v0.0.0-20181114220301-adae6a3d119a
go: finding github.com/Knetic/govaluate v3.0.0+incompatible
go: finding github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373
go: finding github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c
go: finding github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d
go: finding gopkg.in/yaml.v2 v2.2.1
go: finding github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b
go: finding github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec
go: finding golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85
go: finding github.com/pkg/errors v0.8.0
go: finding github.com/go-sql-driver/mysql v1.4.1
go: finding github.com/OwnLocal/goes v1.0.0
go: finding github.com/gomodule/redigo v2.0.0+incompatible
go: finding github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd
go: finding gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
go: github.com/ssdb/gossdb@v0.0.0-20180723034631-88f6b59b84ec: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /root/go/pkg/mod/cache/vcs/3914d3fd5d3f23eecdc3b9eac5ee362289232a8a30aa02518ada098000020213: exit status 128:
    fatal: unable to access 'https://github.com/ssdb/gossdb/': Could not resolve host: github.com; Name or service not known
go: error loading module requirements

重新build即可

go build
  • 处理错误示例

我们使用replace处理这个错误

-replace=golang.org/x/crypto=被替换github.com/golang/crypto@latest

go  mod edit -replace=golang.org/x/crypto=github.com/golang/crypto@latest

这样修改后,在go.mod中就会加入一条replace指令

[root@linuxea.com /opt/Golang/work4]# cat go.mod 
module test

go 1.12

require (
    github.com/astaxie/beego v1.12.0 // indirect
    github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
)

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

6.3第三方包

在使用go mod tidy,go build,go test,go list命令会自动将第三方依赖包写入到go.mod文件中同时下载第三方依赖包到GOPATH/pkg/mod/cache目录,并在当前模块目录生成一个构建状态跟踪文件go.sum,文件中积记录当前module所有的项目和间接依赖,以及这些依赖的校验和

go.mod依赖包

require (
    github.com/astaxie/beego v1.12.0 // indirect
    github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
)

go.sum的签名

[root@linuxea.com /opt/Golang/work4]# cat go.sum 
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y=
github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
  • go build:编译当前模块,当添加一个模块后,就需要仔细go build来下载安装依赖

    • go build -mod=vendor:使用当前模块下的vendor目录中的包进行编译
    • go build ./: 编译当前目录下的所有模块
  • go mod tidy:当删掉一个import的模块的时候,使用go mod tidy就会删掉依赖,从而达到模块的整理(添加新增的,删除未使用的)
  • go mod vendor : 将依赖模块拷贝到模块的vendor目录
  • go mod download:仅下载第三方模块
  • go mod grapha:打印所有第三方模块
  • go list -m -json all:显示所有模块信息
  • go mod edit : 修改go.mod文件

    -require=package@version

    -replace

    =old_package@version=new_package@version

可以使用-replace功能将包替换为本地包,实现相对导入

6.4导入本地库

我们创建一个测试的本地库,如:testmod

[root@linuxea.com /opt/Golang/inTest]# go mod init testmod
go: creating new go.mod: module testmod

创建完成会产生一个go.mod

[root@linuxea.com /opt/Golang/inTest]# cat go.mod 
module testmod

go 1.12

而后创建一个文件夹

[root@linuxea.com /opt/Golang/inTest]# mkdir info

在文件下面创建一个go文件,声明一个全局变量,假设是Name值守mark

[root@linuxea.com /opt/Golang/inTest]# cat info/desc.go 
package info
var Name = "mark"

而后和info的平级目录下创建main.go

这里调用desc.go中的Name全局变量

注意:info下的desc.go中的package 是上级目录名

package main
import (
    "testmod/info"
    "fmt"
)
func main(){
    fmt.Println(info.Name)
}

运行

[root@linuxea.com /opt/Golang/inTest]# go run main.go 
mark
  • 目录结构
[root@linuxea.com /opt/Golang/inTest]# tree ./
./
├── go.mod
├── info
│   └── desc.go
└── main.go

1 directory, 3 files

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论