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

引入后目录结构如下: 目录结构2

此时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"
}

编译能顺利通过

Table of Contents