前言
无论什么Python还是Golang当你的代码量达到一定程度时,就需要使用package来分类、组织我们的代码文件。
go-package概念
在项目开发过程中组织代码的一中方式。包是多个Go文件的集合,是一种高级的代码复用方案,Go语言为我们提供了很多内置包,如fmt
、os
、io
等。
在目前我使用的go1.11.5中每1个.go文件都需要存放在Gopath路径下的1个文件中(包)。
package main
.go文件最开始声明这是1个main包,也就是程序的入口。
初识 go-package
在go语言中1个文件夹可以称为1个包,在文件夹(包)可以创建多个.go文件。
在同1个文件夹(包)中的.go文件必须pakage关键字指定同1个包名。
在go语言中包分为2类
1.main包:使用main包可以让我们写的程序编译成1个可执行的二进制文件,所以main包就是程序的入口。
2.非main包:可以规范和分类我们在程序执行时所需要的功能
如果多个.go文件在同1个文件夹(包)中,那它们就可以直接使用相互的功能,无需导入包。
在包同定义的功能首字母大写,才可以被外部包所调用,否则只能在同1个包中使用。
使用package
定义package
一般来说除了1个程序入口(main包)之外,在Go项目中其他都是我们程序开发人员自由定义的(工具包),以便调用。
mai包可以生成1个可执行文件。
我们使用package关键字定义1个包,
如果当前package想要被其他包调用,那么该工具包中的标识符(变量名、函数名、struct名、interface名)首字母大写表示可见性(对外可见)。
在Go中1个文件夹就是1个package, 所以package中的.go文件一般会和package同名。
programmer.go
package devlepment
import "fmt"
//Programer 大写才能被外部其他包调用
func Programer(name string) {
fmt.Printf(`
I'm %s a programmer work in devlepment department
I interest in programing.in my free time I like seing some Science fiction films ranther than porn.
`, name)
}
init函数
包中的init函数在调用该包时自动执行
package resources
import "fmt"
//init:导入包时自动执行
func init(){
fmt.Println("导入resources包时自动执行")
receptionist("May")
}
func receptionist(nam string){
fmt.Println(`Good morning.may I help you? `)
}
init()函数执行顺序
Go语言包会从main
包开始检查其导入的所有包,每个包中又可能导入了其他的包。Go编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
Golang中1个包可以包含1个init函数,不一样的是这个init函数需要自己定义。
调用包时会最先初始化并调用包中mian函数的init()
函数, 如下图示:
导入package
调用Go里面的包需要从Go project的src目录后面的文件夹开始import。
hello/package_practice/devlepment
package main
import (
//匿名调用包:只调用执行包中init函数中的代码,不使用(pymysql)
_ "hello/package_practice/resources"
//别名:包所在的路径
devlepment "hello/package_practice/devlepment"
sales "hello/package_practice/sales"
finnace "hello/package_practice/finance"
)
func main(){
devlepment.Programer("Sam")
finnace.Contant("Sally")
sales.Salesman("Todd")
}
go mod第三方依赖包管理
为什么需要go mod?
Golang中所有的项目、项目依赖的第三方库,默认情况下全部放在go path/src这1个目录下。
如果要使用N个不同版本的第三方依赖库,应该怎么解决?有没有Python env这种环境隔离机制?
1.godep依赖包管理
Go语言从v1.5开始开始引入vendor
模式,如果项目目录下有vendor目录,那么go工具链会优先使用vendor
内的包进行编译、测试等。
安装
go get github.com/tools/godep
基本命令
godep save 将依赖项输出并复制到Godeps.json文件中
godep go 使用保存的依赖项运行go工具
godep get 下载并安装具有指定依赖项的包
godep path 打印依赖的GOPATH路径
godep restore 在GOPATH中拉取依赖的版本
godep update 更新选定的包或go版本
godep diff 显示当前和以前保存的依赖项集之间的差异
godep version 查看版本信息
使用godep
在项目目录下执行godep save
命令,会在当前项目中创建Godeps
和vender
两个文件夹。
Godeps
文件夹:有一个Godeps.json
的文件,里面记录了项目所依赖的包信息。
vender
文件夹:是项目依赖的包的源代码文件。
vender机制
Go1.5版本之后开始支持,能够控制Go语言程序编译时依赖包搜索路径的优先级。
如果项目require某个依赖包,如果你有vendor目录。
首先会在项目根目录下的vender
文件夹中查找,如果没有找到再去$GOAPTH/src
目录下查找。
godep开发流程
- 保证程序能够正常编译
- 执行
godep save
保存当前项目的所有第三方依赖的版本信息和代码 - 提交Godeps目录和vender目录到代码库。
- 如果要更新依赖的版本,可以直接修改
Godeps.json
文件中的对应项
2.go module依赖包管理
go module
是Go1.11版本之后官方推出的版本管理工具, G01.12功能基本稳定。 并且从Go1.13版本开始,go module
将是Go语言默认的依赖管理工具。
0.如果你使用的是go 1.13之前的版本,那么在使用go mod之前需要手动开启对go mod的支持:
要启用go module
支持首先要设置环境变量GO111MODULE
,通过它可以开启或关闭模块支持,它有三个可选值:off
、on
、auto
,默认值是auto
。
-
GO111MODULE=off
禁用模块支持,编译时会从GOPATH
和vendor
文件夹中查找包。 -
GO111MODULE=on
启用模块支持,编译时会忽略GOPATH
和vendor
文件夹,只根据go.mod
下载依赖。 -
GO111MODULE=auto
,当项目在$GOPATH/src
外且项目根目录有go.mod
文件时,开启模块支持。
简单来说,设置GO111MODULE=on
之后就可以使用go module
了,以后就没有必要在GOPATH中创建项目了,并且还能够很好的管理项目依赖的第三方包信息。
使用 go module 管理依赖后会在项目根目录下生成两个文件go.mod
和go.sum
。
go.mod:有的像node.js的pakage.json存储当前项目所有依赖库的版本
go.sum:所有依赖的集合
我使用的就是go1.13所以不需要每次都开启go mod模式。
D:\goproject\src>go env
set GO111MODULE=on
set GOPROXY=https://goproxy.cn
go mod命令
我们使用go mod无非处于2种目的
目的1.我自己开发的项目生成go.mod让别人同步我的依赖包
目的2.别人写得项目,我跟他的依赖包版本保持一致。
go mod get
go mod download 从github或者指定代理下载第三方依赖---->本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit 编辑go.mod文件
go mod graph 打印模块依赖图
go mod init 初始化当前文件夹, 创建go.mod文件
go mod tidy 整理依赖(增加缺少的module,删除无用的module)校验go mod中设置的版本和D:\goproject\pkg\mod中的版本是否一致!
go mod vendor 将依赖复制到vendor下
go mod verify 校验依赖
go mod why 解释为什么需要依赖
自己生成go.mod流程
D:\goproject\src\go相关模块\kafka>SET GO111MODULE=on
D:\goproject\src\go相关模块\kafka>SET GOPROXY=https://goproxy.cn
D:\goproject\src\go相关模块\kafka>go mod init
go: creating new go.mod: module go相关模块/kafka
D:\goproject\src\go相关模块\kafka>go mod download
go: finding github.com/Shopify/sarama v1.19.0
go mod文件语法
go.mod文件记录了项目所有的依赖信息,其结构大致如下:
module jd.com/logagent //当前包名
go 1.13 //go版本
require ( //在这里指定第三方依赖库的版本信息
github.com/Shopify/sarama v1.19.0
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/hpcloud/tail v1.0.0
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
replace语法
在国内访问golang.org/x的各个包都需要FQ,你可以在go.mod中使用replace替换成github上对应的库。
replace (
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac
golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d
golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)
go get
在项目中执行go get
命令根据go.mod中指定的依赖包进行下载,并且还可以指定下载的版本。
- 运行
go get -u
将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号) - 运行
go get -u=patch
将会升级到最新的修订版本 - 运行
go get package@version
将会升级到指定的版本号version
如果下载所有依赖可以使用go mod download
命令。
3.运行1个gin项目
我使用go 1.14版本结合go mod,在go path之外运行1个gin项目。
mkdir zhanggen
cd zhanggen
go mod init zhanggen
ls
pwd //在/zhanggen目录下多个1个go.mod文件
cd zhanggen
SET GOPROXY=https://goproxy.cn //设置代理加速下载
go mod环境已经准备完毕 ,开始写代码吧。
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
代码写完了就开始运行代码吧。
D:\zhanggen>go run main.go
go: finding module for package github.com/gin-gonic/gin
go: found github.com/gin-gonic/gin in github.com/gin-gonic/gin v1.6.3
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /ping --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
4.依赖包版本迭代
修改go.mod文件中的require版本即可。
5.重启
go mod第三方包管理比Python还方便,不用自己去 pip install requirement.txt了。
运行时自动根据go.mod更新。
D:\zhanggen>go run main.go
go: downloading github.com/gin-gonic/gin v1.6.2 自动去下载和切换版本了 6666
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)