前言
无论什么Python还是Golang当你的代码量达到一定程度时,就需要使用package来分类、组织我们的代码文件。
一、Package概念
包在项目开发过程中组织代码的1种方式。
包是多个Go文件的集合,是一种高级的代码复用方案,Go语言为我们提供了很多内置包,如fmt
、os
、io
等。
在目前我使用的go1.11.5中每1个.go文件都需要存放在Gopath路径下的1个文件中(包)。
package main
.go文件最开始声明这是1个main包,也就是程序的入口。
1.初识 go-package
在go语言中1个文件夹可以称为1个包,在文件夹(包)可以创建多个.go文件。
在同1个文件夹(包)中的.go文件必须pakage关键字指定同1个包名。
在go语言中包分为2类
1.main包:使用main包可以让我们写的程序编译成1个可执行的二进制文件,所以main包就是程序的入口。
2.非main包:可以规范和分类我们在程序执行时所需要的功能
如果多个.go文件在同1个文件夹(包)中,那它们就可以直接使用相互的功能,无需导入包。
在包同定义的功能首字母大写,才可以被外部包所调用,否则只能在同1个包中使用。
2.使用package
2.1定义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) }
2.2.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? `) }
2.3.init()函数执行顺序
Go语言包会从main
包开始检查其导入的所有包,每个包中又可能导入了其他的包。Go编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
Golang中1个包可以包含1个init函数,不一样的是这个init函数需要自己定义。
调用包时会最先初始化并调用包中mian函数的init()
函数, 如下图示:
2.4.导入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") }
二、第3方依赖包下载
以上是Golang管理依赖包的机制,那怎么下载第三方依赖包呢?
不同于Python和Node在Go种没有1个中心化管理第3方依赖的源,都是去github下载。
在项目中执行go get
根据go.mod中指定的依赖包进行下载(相当于pip install ),并且还可以指定下载的版本。
- 运行
go get -u
将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号) - 运行
go get -u=patch
将会升级到最新的修订版本 - 运行
go get package@version
将会升级到指定的版本号version
下载所有依赖可以使用go mod download
命令。
二、第3方依赖包管理
Golang源自于谷歌内部,由于是最初是内部开发,根本没有第三方依赖包管理机制;
所以一直再不断完善。
Golang项目依赖的第3方依赖包,默认情况下全部放存储go path/src目录下。
1.Gopath
Gopath是存储Go第3方依赖包的路径(相当于Python的sitepackage目录)
之前需要手动配置GoPath,Golang1.8及之后的版本自动设置GOPATH=$HOME/go
2.Vender机制
Go1.5版本之后开始支持,能够控制Go语言程序编译时依赖包搜索路径的优先级。
如果项目require某个依赖包,如果你有vendor目录。
首先会在项目根目录下的vender
文件夹中查找,如果没有找到再去$GOAPTH/src
目录下查找。
3.Go mod
Golang 1.12 有了 Go Modules 后,可以把Go 项目放在任何地方。
Go mod
是Go1.11版本之后官方推出的版本管理工具, G01.12功能基本稳定。
从Go1.13版本开始,go module
将是Go语言默认的依赖管理工具。
D:\goproject\src>go env set GO111MODULE=on set GOPROXY=https://goproxy.cn
3.1.go mod命令
我们使用go mod无非处于2种目的
目的1.我自己开发的项目生成go.mod让别人同步我的依赖包
目的2.别人写得项目,我跟他的依赖包版本保持一致。
go get 从github或者指定代理下载第三方依赖---->本地cache(默认为$GOPATH/pkg/mod目录)
go mod download 根据gomod文件下载指定版本的依赖包
go mod edit 编辑go.mod文件 go mod graph 打印模块依赖图 go mod init 初始化当前文件夹, 创建go.mod文件 go mod tidy 整理go.mod中依赖(增加缺少的module,删除无用的module)校验go mod中设置的版本和D:\goproject\pkg\mod中的版本是否一致! go mod vendor 需要在离线环境开发、编译时,将第3方依赖包复制到当前项目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引入了go.mod文件来标记每个依赖包的版本,在构建过程中go命令会下载go.mod中的依赖包,下载的依赖包会缓存在本地,以便下次构建。
考虑到下载的依赖包有可能是被黑客恶意篡改的,以及缓存在本地的依赖包也有被篡改的可能,单单一个go.mod文件并不能保证一致性构建。
为了解决Go module的这一安全隐患,Go开发团队在引入go.mod的同时也引入了go.sum文件,用于记录每个依赖包的哈希值。
在构建时,如果本地的依赖包hash值与go.sum中记录的hash值不一致,则会拒绝构建。
4.离线安装Go依赖包
在离线环境开发时除了使用内网Goporxy代理,还可以采用以下方式解决Go依赖包下载问题。
4.1下载go项目的依赖包
导出项目需要的go.mod文件,放到联通外网环境的机器上。
外网机器配置GOMODCACHE
go env -w GOMODCACHE="C:\your\path\pkg\mod"
在go.mod所在的文件夹下,执行
go mod download
这样go.mod里的依赖包将会下载到$GOMODCACHE下缓存起来,以便于后期Go编译器进行项目的编译构建。
打包$GOMODCACHE/cache/download文件夹,生成download.zip包。使用文件摆渡传到离线云桌面。
4.2.搭建内网环境文件服务器
将download.zip文件导入服务器中,放到/export/package/go_download下。
登录服务器(例1.1.1.1),启动文件服务器
cd /export/package/go_download python3 -m http.server 8010
4.3.离线云桌面
需要下载go依赖包的项目设置GOPROXY=http://1.1.1.1:8010
go env -w GOPROXY=http://1.1.1.1:8010
开始从内网文件服务器下载go依赖包
设置GoRoot
export GOOROOT=/usr/local/go
整理项目中包含的go.mod文件
/usr/local/go/bin/go mod tidy
根据go.mod中指定的依赖包版本,从内网文件服务器下载go依赖包
/usr/local/go/bin/go mod download
5.Goland/Pycharm离线环境下安装插件
在离线环境下使用Goland、Pycharm连接数据库,需要下载各种数据库的drivers,这些drivers保存在本机的如下目录下
C:\Users\GIENTECH\AppData\Roaming\JetBrains
6.gvm管理不同Golang版本
通过设置GO_BINARY_BASE_URL系统环境变量加速go install;
ENV GO_BINARY_BASE_URL=https://mirrors.aliyun.com/golang/ RUN /bin/bash -c 'source /root/.gvm/scripts/gvm; gvm install go1.23.0 -B;' CMD ["sh"]