go 1.11のmodules(vgo)が有効な環境で相対importが cannot find module for path でエラーになった話。

vgoが有効な環境の場合に相対importがエラーになる

時折、GOPATH外で作業したりするときなどに相対importが使いたくなる。例えば以下の様な構成でxxx packageの関数を利用したい。

.
├── main.go
└── xxx
    └── hello.go

1 directory, 2 files

xxx/hello.go

package xxx

import "fmt"

// Hello :
func Hello() {
    fmt.Println("hello")
}

main.go

package main

import (
    "./xxx"
)

func main() {
    xxx.Hello()
}

以前まではGOPATH外で書いたgoのコードでファイルを分けたpackageを読み込んで利用したいときには、このような形で相対importを使うことができた。一方でgoのmodules(vgo)が有効な環境では上手くpackageを探すことができずにエラーになる。具体的には以下の様なエラー。

go run 00*/main.go
build github.com/podhmo/<mypkg>/00ng: cannot find module for path _$HOME/venvs/my/<mypkg>/00ng/xxx

対応方法

対応方法は2つある。1つはmodullesを無効にする方法。もう一つはgo.modを書く方法。

modulesを無効にする方法

wikiによると、GO111MODULEという環境変数に値を設定することで有効・無効を指定できる(defaultはauto)。

$ GO111MODULE=on  # 有効
$ GO111MODULE=off # 無効

なので、暫定的な対応としては以下の様な形で無効にして呼んであげれば良い。

$ GO111MODULE=off go run 00*/main.go
hello

go.mod

もう一つの方法はmodulesの機能を使って解決する方法。

# go.modを作成する(package名はmainでも何でも良い)
$ go mod init m

go.mod

module m

以下のように書き換える(mはgo.modで指定したpackage名)

--- 00ng/main.go 2018-12-26 07:15:18.837219706 +0900
+++ 01ok/main.go  2018-12-26 07:31:33.159657145 +0900
@@ -1,7 +1,7 @@
 package main
 
 import (
-  "./xxx"
+   "m/xxx"
 )

相対的な位置ではなく、mというpackageのsub packageという意味(ここでmはgo.modで指定したpackage名)。

今度は大丈夫

$ go run main.go
hello

こちらの方法の方が筋が良さそう。go modulesでGOPATHから解放されようとしている感じなので(全てのimport pathに完全修飾で指定するという世界観)。

実際の所goのrepositoryでもissueがあげられていて、そのissueの中では、残念だけれど想定通りの挙動で、相対import自体が古いgoでの半ば場当たり的に付けられた機能という返答がされている。