go-包 5-2
包的概念
包是结构化代码的一种方式:每个程序都由包(通常简称为 pkg)的概念组成,可以使用自身的包或者从其它包中导入内容
如同其它一些编程语言中的类库或命名空间的概念,每个 Go 文件都属于且仅属于一个包。一个包可以由许多以 .go 为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的
你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main 。
package main 表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。package main 包下可以有多个文件,但所有文件中只能有一个 main () 方法,main () 方法代表程序入口
每一个程序可以包含不同的包,且即使你只使用main包也不必把所有的代码都写在一个恒大的文件里: 你可以用一些较小的文件,组成每个文件非注释的第一行都使用
package main指明这文件都属于main包。如果你打算编译包名不为main的源文件,如pack1,编译后产生的对象文件将会是pack1.a不可执行程序。另外要注意的是,所有的包名都应该使用小写。当然, main 包是不能在其他文档import的,编译器会报错:
- 包(packge)多个Go源码的集合,是一种高级的代码复用方案, Go语言为我们提供了很多内包,如:fmt、strconv、 strings、 sort、 eros、 time、encoding/json、 OS、 io等
- Golang 中的包可以分为三种: 1、系统内包2、自定义包3、第三方包 。系统内包:Golang语言给我们提供的内包,引入后可以直接使用,如fmt、srconv、strings、 sort.eros、time、 encoding/json、 os、 io 等
- 定义包:发者自己写的包
导入
一个Go程序是通过import关键字将-组包链接在一起。
import “fmt” 告诉Go编译器这个程序需要使用fmt包(的函数,或其他元素),fmt 包实现了格式化10 (输入1输出)的函数。包名被封闭在半角双引号""中。如果你打算从已编译的包中导入并加载公开声明的方法,不需要插入已编译包的源代码。
import其实是导入目录,不定义的package字,虽然我们一般都会保持一致, 实是可以随便定义目录名,只是使用时会很容易混乱,不建议这么做。
当你导入多个包时,好按照字母顺序排列名,这样做更加清晰易读。
import 和 package 的使用
golang使用包package来管理定义模块,可以使用import关键字来导入使用。
- 如果导入的是go自带的包,则会去安装目录$GOROOT/src按包路径加载,如fmt包
- 如果是我们go get安装或自定义的包,则会去$GOPATH/src下加载
package的定义
注意 相信对很多phper来说遵循PSR4的Namespace会将与路径紧密相关命名空间也作为类名的一部分,而golang则只将模块目录文件夹名作为包名,前面的路径只是用来导入而和包名无关,还是有一点点需要注意的。
package的存放位置是以$GOPATH/src作为根目录,然后灵活的按照目录去组织,且包名需与最后一级目录名一致。
例如我们自定义baz包,包模块的存放位置则为$GOPATH/src/foo/bar/baz, baz 包的源码都存放在此目录下,foo/bar/baz则作为包路径被import载入。
我们需要规范的将baz包中源码的package定义为baz,就定义好一个可import载入的的包了。
栗子:
D:\phpstudy_pro\go\src\pay\alipay.go
package pay
import (
"fmt"
)
func Alipay() {
fmt.Println("Alipay is good !!!")
}
D:\phpstudy_pro\go\src\pay\wechat\wechat.go
package wechat
import (
"fmt"
)
func Wechat() {
fmt.Println("Wechat is good !!!")
}
注意作用域
- 声明在函数内部,是函数的本地值,类似private
- 声明在函数外部,是对当前包可见(包内所有.go文件都可见)的全局值,类似protect
- 声明在函数外部且首字母大写是所有包可见的全局值,类似public
import的定义
常用方式
import (
"pay"
"pay\wechat"
)
func main(){
pay.Alipay()
wechat.Wechat()
}
普通导入就是按照加载机制,将要使用的包导入进来,然后使用 packageName.MethodName 的方式调用包内的方法即可。
注意 如果要包方法在其他包中可以调用,包方法需要首字母大写,例如:fmt.Println() fmt.Printf()。
别名方式
如果两个包的包名存在冲突时,我们可以使用别名导入来解决。
import (
"pay"
wec "pay\wechat"
)
func main(){
pay.Alipay()
wec.Wechat()
}
自定义包packge包名
- 一个文件夹下面直接包含的文件只能归属一个 packge,同样一个 packge 的文件不能在多个文件夹下
- 包名可以不和文件夹的名字一样,包名不能包含 - 符号
- 包名为 main 的包为应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含 main 包的源代码则不会得到可执行文件
go mod
这是一个go的包管理工具
在Golang1.11版本之前如果我们要自定义包的话必须把项目放在GOPATH 里。Go1.11版本之后无需手动配置环境变量,使佣go mod管理项目,也不要非得把项目放到GOPATH指定录下,你可以在你磁盘的任何位置新建一个项目 , Go1.13以后可以彻底不要GOPATH了。
go mod int初始化项目
D:\phpstudy_pro\WWW\gone
//执行:
go mod init gone
注意上面执行的位置是在对应包的目录下,会在该目录下生成go.mod文件
go.mod
module bao
go 1.16
go mod 命令
命令 | 作用 |
---|---|
dowmload | 下载依赖的module到本地 |
edit | 编辑go.mod文件 |
graph | 打印模块依赖图 |
init | 在当前文件夹下初始化一个新的module,创建go.mod文件 |
tidy | 增加丢失的module,去掉未用的module |
vendor | 将依赖复制到vendor下 |
verify | 校验依赖 检查下载的第三方库有没有本地修改,如果有修改,则会返回非 0,否则验证成功。 |
why | 解释为什么需要依赖 |
快速迁移项目至 Go Modules
- 第一步: 升级到 Go 1.13。
- 第二步: 让 GOPATH 从你的脑海中完全消失,早一步踏入未来。
修改 GOBIN 路径(可选):go env -w GOBIN=$HOME/bin。
打开 Go modules:go env -w GO111MODULE=on。
设置 GOPROXY:go env -w GOPROXY=https://goproxy.cn,direct # 在中国是必须的,因为它的默认值被墙了。 - 第三步(可选): 按照你喜欢的目录结构重新组织你的所有项目。
- 第四步: 在你项目的根目录下执行 go mod init <OPTIONAL_MODULE_PATH> 以生成 go.mod 文件。
- 第五步: 想办法说服你身边所有的人都去走一下前四步。
栗子
在一个新的目录下新建一个文件夹 hello
在这个目录下执行
go mod init hello
创建main.go
//hello 是go mod init 的这个 hello
package main
import (
"fmt"
"github.com/jinzhu/configor"
"hello/route"
)
func main() {
fmt.Println("使用外部包测试:", configor.Config{})
fmt.Println("使用内部包测试:", route.GetName())
}
目录下执行 go get github.com/jinzhu/configor
新建 route 在hello目录下
新建route.go
package route
func GetName() string{
name := "route"
return name
}
发布自定义的包
去github创建新项目
https://github.com/indada/go-csmod
上传
email.go
package sms
import "fmt"
func init() {
fmt.Println("this is sms/email.go init")
}
func Email() {
fmt.Println("this is sms email")
}
git操作
git init
git add *
git commit -m "go"
git branch -M main
git remote add origin https://github.com/indada/go-csmod
git push -u origin main
下载运用
go get -u github.com/shineyork/go-sms
git上的包要先发布才能下载
package main
import (
"fmt"
"github.com/jinzhu/configor"
"hello/route"
cs "github.com/shineyork/go-sms"
)
func main() {
fmt.Println("使用外部包测试:", configor.Config{})
fmt.Println("使用内部包测试:", route.GetName())
cs.Email()
}
this is sms/email.go init
使用外部包测试: { false false false false 0s <nil> false}
使用内部包测试: route
this is sms email
基于go.mod完善组件
go.mod它和我们php的composer,java的maven是很相似的因此它正常也是可以去帮助我们来下载所需要的组件到本地的项目中以便于项目的开发;
需要说明的是go.mod与版本号关系:
- Go modules 狠到如果你的 Tag 没有遵循语义化版本控制那么它就会忽略你的 Tag,然后根据你的 Commit 时间和哈希值再为你生成一个假定的符合语义化版本控制的版本号
- Go modules 还默认认为,只要你的主版本号不变,那这个模块版本肯定就不包含 Breaking changes,因为语义化版本控制就是这么规定的啊
那如何下载呢?
对于modules来的go项目来说如果我们需要引入我们想要的组件则就需要在go.mod目录下运行 go get xxx/xxx/xx
如下载:github.com/cosiner/argv
go get github.com/cosiner/argv
注意代理GOPROXY
需要值得注意这个地方可能会存在下载的网络慢的问题、我们需要设置go env的GOPROXY为:https://mirrors.aliyun.com/goproxy/
设置命令
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/
proxy 顾名思义就是代理服务器的意思。大家都知道,国内的网络有防火墙的存在,这导致有些Go语言的第三方包我们无法直接通过go get命令获取。GOPROXY 是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置环境变量 GOPROXY 即可
go mod对下载包的要求
- 包的go mod中module定义规范必须要以 github.com 或者其他平台的域名作为定义前缀;后跟上项目目录地址
- github的包必须要有发布版本
下一篇:go 反射 6
上一篇:go-设计模式5-1