在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:golangNodeproject 9296day
来添加
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