これまで、mainパッケージだけで済ませられるようなコードくらいしかGo言語で書くことがなかったのですが、 ちょっと複雑なことをやろうと思い、自作パッケージに手を出したらimport周りでハマったのでメモ。

正確にはハマったと言うよりも、Go言語のお作法を理解せずに書いていいたのが原因だったのですが、、、

ワークスペースを理解して問題解決

ハマったところ

以下のようのなディレクトリ構成で、bar.goからfooパッケージをimport ../fooのように相対パス指定すると IntelliJでUnresolved referenceと関数を呼び出すときに怒られてしまった。

.
├── bar
│   └── bar.go
├── foo
│   └── foo.go
└── main.go

ついでに、自作パッケージを以下のようにインポート(go getなしで)できるようにしたい。

import "github.com/[username]/[repo-name]"

原因

参考URLドキュメントを確認すると、 Go言語的に ./ または ../ の相対パスをサポートしているようですが、推奨していないようです。

To avoid ambiguity, Go programs cannot use relative import paths within a work space.
> あいまいさを避けるため、Goプログラムは作業領域内の相対インポート・パスを使用できません。

どうやら、相対パスは簡単にマルチパッケージを検証するための機能のようですね。

This makes it easy to experiment with small multipackage programs outside of the usual work spaces.
> 通常の作業スペースの外にある小さなマルチパッケージプログラムを使って簡単に試すことができます。

対策

ワークスペース内で開発する事で問題が解決できました。
ワークスペースとはGOPATH環境変数で指定したディレクトリで、未指定の場合$HOME/goとなるようです。

また、import "github.com/[username]/[repo-name]"としたい場合、

cd $GOPATH
mkdir -p src/github.com/[username]/[repo-name]

として、src/github.com/[username]/[repo-name]配下で開発を行います。

なお、私の場合は次の項で話題にする部分から逸脱してしまいますが、IntelliJでコードを書くことを優先に

$ export $HOME/.go:$HOME/Development/golang

と、GOPATHを2つ設定しています。
一応、go getコマンドで取得したパッケージは全て 先頭 に記載されたパスになるとのことらしいので、、、 とりあえず現状問題は発生していないように見受けられます。

ワークスペースについて

ドキュメント(オーバービュー)を読むと、

すべてのプロジェクトが別々のワークスペースを持ち、ワークスペースがバージョン管理リポジトリと緊密に結びついている他のプログラミング環境とは異なります。

  • 通常、すべてのGoコードを1つのワークスペースに保持します
  • ワークスペースには、多くのVersion Controlのリポジトリが含まれます(Gitなど)
  • 各リポジトリには1つ以上のパッケージが含まれています。
  • 各パッケージは、1つまたは複数のGoソースファイルで構成されています。
  • パッケージのディレクトリへのパスによって、インポートパスが決まります。

だ、そうです。

感想

ちょこっと触っただけでも動くものが開発できるGo言語の魅力を改めて感じました。
しかし、このワークスペースの概念はIDEに慣れているとちょっと厄介ですよね?w

参考

以上。