Go语言入门到实战——00主目录 在上一讲中我们学习了Go语言的错误处理的知识。

一.Go语言package的特点

1.基本复用模块单元:
	以首字母大写来表明可被包以外的代码访问。如函数,结构体(或其成员名)
	等定义时首字母大写代表可以被外包的代码访问
2.代码的package可以和所在的目录名不一致,但是在同一个目录下的
	不同文件所在包的包名需要一致(这个读者可以自己实验)

首先我先讲一个自己构建可复用包的案例:

//现在我的项目目录结构如下:(位于E:\go_workspace\go_helloproject)
go_helloproject:
	src:
		hello:
			add.go
		test:
			addUse_test.go

先在命令行使用go env来查看go语言的导包路径GOPATH:

//我的是:
GOPATH=C:\Users\Administrator\go
//我们需要添加我们的包路径使其成为可复用包,设置的原则就是一直到src的前一步
//(src时默认的可以导包的位置),因此在搭建的时候注意先建src包在继续构建其它
//最后的结果是下面这样,具体设置方法根据Windows系统和Linux系统可自行百度
//注意Linux应该把下面的分号改为冒号':'
GOPATH=C:\Users\Administrator\go;E:\go_workspace\go_helloproject
//修改完记得重启IDE

add.go的代码如下

//add.go
package hello_add

func add(a int, b int) int {
	return a + b
}

addUse_test.go

//addUse_test.go
package testAdd

import (
	hello_add "hello"//这里由于hello目录下的add.go的包名
					 //为hello_add,所以导入时需要起别名为其包名(其实也可以不是包名
					 //,但是必须起别名,随便什么都可,不过建议和包名一致)
					 //当然如果add.go的包名就是hello,那么就不需要使用别名了
	"testing"
)

func TestAdd(t *testing.T) {
	t.Log(hello_add.Add(1, 2))
}

接下来我们测试下大写字母的问题:

//在add.go中添加这个函数
func square(a int) int {
	return a * a
}

go语言Gin框架实战 go语言模块_开发语言

二.init方法

1.在main/test被执行之前,所以依赖的package的init方法都会被执行
2.不同包的init方法按照包的导入依赖关系决定执行的顺序
3.每个包可以有多个init方法
4.包的每个源文件也可以有多个init方法,这点比较特殊

在add.go里面添加下面内容:

func init() {
	fmt.Println("init1")
}

func init() {
	fmt.Println("init2")
}

执行测试如下(在输出Add方法的结果前,init先被执行了,并且是按照在源文件add.go里面的顺序执行的):

go语言Gin框架实战 go语言模块_ide_02

三.远程package的使用

//我们使用go get 命令下载包:
//-u表示会更新依赖和对应的下载的包,不使用-u那么对于已经存在的包或者依赖不会去更新
//https://github.com/easierway/concurrent_map.git的https://和.git都要去掉
go get -u github.com/easierway/concurrent_map

在下载包时我出现了git clone出现错误 fatal: unable to access ‘https://github.com/…‘的解决办法

package testAdd
import (
	"testing"
	cm "github.com/easierway/concurrent_map"
)

func TestConcurrentMap(t *testing.T) {
	m := cm.CreateConcurrentMap(99)
	m.Set(cm.StrKey("key"), 10)
	t.Log(m.Get(cm.StrKey("key")))
}

go语言Gin框架实战 go语言模块_ide_03


最后需要强调的一点就是在提交自己的源码到github时不要把src也提交了,不然git get就会找不到,即直接以代码路径开始,不要有src。

四.依赖管理

Go语言依赖管理其实并不完善,还有下面两个未解决的问题

1.同一环境下,不同项目使用同一包的不同版本没有实现
	get下来的包会放在Gopath里面,项目在查找包时会现在Gopath里面寻找,然后在从Goroot里面去找,
	这样会造成所有的项目使用的是同一个版本的包,而自己特定的包版本就无法使用了
2.无法管理对包的特点版本的依赖
	我们在使用get是发现从来没有指定过包的版本,因此缺乏对特定版本的报的依赖管理

那么为了解决上面的问题官方给出了vendor路径来解决这一问题。

vecdor目录是被添加到GOPATH和GOROOT之外的依赖目录的查找解决方案。这个在Go1.6之前需要自己手动
设置环境变量
有了vendor目录后查找包的解决方案就是:
1.当前包的vendor目录
2.向上级目录查找,直到找到src下的vendor目录
3.在GOPATH下查找依赖包
4.在GOROOT下查找依赖包

常见的依赖管理工具充分利用了vendor来帮我们做到;

1.godep:https://github.com/tools/godep (比较早期了)
2.glide:https://github.com/Masterminds/glide
3.dep:https://github.com/golang/dep (相比于前两个是最新的)

下面演示glide:

1.安装glide(Linux)
brew install glide

不过在Windows下使用会有一些bug,参加这篇文章修正
cs
最后生成glide.exe是在glide目录下使用go build即可,最后替换掉go/bin下的glide.exe

接下来我们以上面的concurrent_map为例来进行演示

1.进入到测试concurrent_map的go文件所在包,然后执行glide init,后面的可以根据需要自行选择
此时会在当前目录生成一个ymal文件,里面记载了当前目录下所有文件你所依赖的包,我们这里就是
concurrent_map包
2.glide install
表示根据yaml文件的内容进行依赖包下载,并且会生成vendor目录
这样我们就可以在vendor目录下使用我们自己想要的版本包了(指定版本可以在ymal里面修改
如果报update失败可能就是版本号的问题,这就需要自己修改对了)

go语言中go.mod文件有什么用