module其实是在go1.12才有的产物,在这之前都是由GOPATH来做包管理, GOPATH注定是要退出历史,这里来说一说module跟package的关系.
通常一个项目(Project)会根据功能拆分很多模块(module), golang 的所有文件都需要指定其所在的包(package)
package
一个包可以分成多个文件, 在编译的时候会被组合成一个文件.
包名跟所在的目录的名字可以不一样(跟文件本身的名字更没关系), 但同一个目录下的所有文件的包名字必须相同
比如这样, second目录下有两个go文件, others.go, second.go, 同时有一个third目录
1 | second |
cat others.go
1 | package others // 正确的为package api |
cat second.go
1 | package api |
在second.go中声明的包名为api, 这个时候会提示如下错误, 说两个文件的包名不一致.
can't load package: package govars/second: found packages others (others.go) and api (second.go) in /Users/zhoushuke/git_uni/zhoushuke.github.com/learn-golang/golang-vars/second
因此可以把两个文件都改成package api
保持一致即可, 这里也说明了包名跟目录名可以不同
在main函数中可以这样调用
1 | package main |
因此: 可以这样理解,import 的是 path(路径),那么go就去那个路径下搜索,搜索当然是查找包名。只不过通常习惯是 文件名和 包名一致
假如现在third.go的文件也被声明为package api
cat third/third.go
1 | package api |
second.go也是package api, 这两者是不会冲突的, 因为third.go是在third目录下, second.go在second目录下,
但是在main函数中调用就会有问题
1 | package main |
解决方法就是在import时,为导入的包添加别名
1 | package main |
module
在go1.11之后开始支持module, 在1.13后全面铺开,当然也是兼容GOPATH方式
在module的方式之下的代码组织结构会有些不同.
这里主要理使用go mod引用本地包的问题.
最终目录结构:
1 | learn-golang/golang-mod |
生成以上目录的命令如下:
1 | cd learn-golang/golang-mod |
这里go.sum文件暂时不管, go.sum是一个构建状态跟踪文件。它会记录当前module所有的顶层和间接依赖,以及这些依赖的校验和,从而提供一个可以100%复现的构建过程并对构建对象提供安全性的保证
代码都是非常简单, first.go代码如下:
1 | package first |
second.go代码如下:
1 | package second |
main.go代码如下:
1 | package main |
生成的first目录下的go.mod文件如下:
由于second.go中引用了logrus, 因此在run的时候会进行下载
最终生成的second目录下的go.mod文件如下:
而在main.go, 引用了first及second, 如果不在最外层的go.mod中使用replace来指定到本地的话, 那go 会直接通过这个地址进行下载, 那当然会报错
因此需要在最外层的go.mod中使用replace, 指定到本地的first及second目录
从上面可以看出, 虽然second.go中使用了logrus, 但在最外层的go.mod中并没有require logrus,因为main.go中并没有用到, 如果在main.go中使用了logrus, 则在go.mod中也会出现.
运行结果如下: