Go Vendor嵌套引用的坑
1.背景
- 公司里有很多大神造好了很多好用的轮子
- 项目核心组件独立维护
- 具体各个项目直接复用核心组件
2.举例
2.1.目录结构
workspace=$GOPATH/src/snowwalf.com
2.2.代码
// snowwalf.com/c/c.go
package c
type C struct {
C int
}
// snowwalf.com/b/b.go
package b
import "snowwalf.com/c"
type B struct {
C c.C
}
// snowwalf.com/a/a.go
package a
import (
"snowwalf.com/b"
"snowwalf.com/c"
)
func main() {
var c c.C
b := b.B{
C: c,
}
return
}
2.3.编译结果
➜ a go build
# snowwalf.com/a
./a.go:11:4: cannot use c (type "snowwalf.com/a/vendor/snowwalf.com/c".C) as type "snowwalf.com/b/vendor/snowwalf.com/c".C in field value
可见,a中的struct C引用的是snowwalf.com/a/vendor/snowwalf.com/c 中的定义,而b中的struct C是引用的snowwalf.com/b/vendor/snowwalf.com/c 虽然两边vendor都是源于snowwalf.com/c 但编译器认为两边的对象不是同一个,无法转换
3.原因
对于这个问题,官方对vendor的解释如下
- If there is a source directory d/vendor, then, when compiling a source file within the subtree rooted at d, import “p” is interpreted as import “d/vendor/p” if that exists.
- When there are multiple possible resolutions,the most specific (longest) path wins.
- The short form must always be used: no import path can contain “/vendor/” explicitly.
- Import comments are ignored in vendored packages.
另外可以参考下这篇vendor的介绍 https://tonybai.com/2015/07/31/understand-go15-vendor/
4.解决方案
目前来看,就是在a中直接用govendor引入b,govendor会把b包的vendor拆开合并进a的vendor中
govendor add +outside snowwalf.com/b
引入后目录结构如下:
此时a的vendor.json如下
{
"comment": "",
"ignore": "test",
"package": [
{
"checksumSHA1": "w+ypFY+WdRVG/hI8HCxiLg/vbWM=",
"path": "snowwalf.com/b",
"revision": ""
},
{
"checksumSHA1": "VFI5gTBQiN8SQcMN7r/E8FBSqSY=",
"path": "snowwalf.com/c",
"revision": ""
}
],
"rootPath": "snowwalf.com/a"
}
编译能顺利通过