【Go言語】GOPATHの外に作ったプロジェクトでサブパッケージをインポートする

2020/09/16に公開

Go言語に入門中の身です。A Tour of Goをやり終えたところです。

手元のお試し用のコードが増えるにつれて、main.goファイルに収まらなくなり、ファイルを分割したい欲求にかられ始めた頃、壁にぶつかりました。

ローカルファイルのインポートができない!

ソースコードを以下のように配置して……

zenn-first-article
├── main.go
└── zenn
    └── zenn.go
// zenn.go
package zenn

// Article describes a zenn article meta
type Article struct {
	Slug      string
	Title     string
	Emoji     string
	Type      string
	Topics    []string
	Published bool
}

main.goから./zenn/zennのようにインポートすると……

// main.go
package main

import (
	"fmt"
	"./zenn/zenn"
)

func main() {
	fmt.Println("Hello, Zenn!")
	item := zenn.Article{}
	fmt.Printf("%v\n", item)
}

以下のようなエラーが発生。。

main.go:6:2: local import "./zenn/zenn" in non-local package
exit status 1
Process exiting with code: 1

GOPATHとは一体……?

golang import local packageなどと検索してみても、いまいちピッタリはまる情報がヒットしません。どうにか得られた情報はこんな感じ

  • 環境変数GOPATHにセットしたパスの下にすべてのプロジェクトを配置するのが基本
  • ローカルパッケージをインポートするときも($GOPATH/src以下からの)絶対パスを使う
  • ローカルパッケージのインポートでも相対パスは非推奨
  • バージョン1.11から導入されたgo modulesという仕組みがある
  • go modulesを使うと、プロジェクトをGOPATHの外に配置できる

go modulesを試してみる

「GOPATH(何も設定しなければ、~/goになる)の下に全部のプロジェクトを置く?!なにそれ!」
「ローカルパッケージの相対パスでのインポートは非推奨?!」
などとびっくりしつつ……

go modulesというのを使えばよいのね。と思いながら使い方を調べると、GitHubなどにホスティングされている外部パッケージを管理する仕組みのようです。
しかし、自分で作成したローカルパッケージをインポートする方法がいまいちわからない。。

たしかに$GOPATH/src/zenn-first-articleにプロジェクトのディレクトリを配置すれば、

// main.go
package main

import (
	"fmt"
	"zenn-first-article/zenn"
)

のようにインポートできるようにはなるのですが、npmやbundlerのようなパッケージ管理ツールに慣れた身にとっては違和感がすごいです。

解決策

なんだかもんにょりして、Twitterでつぶやいたところ、親切な方がgo modulesの使い方を教えてくださいました!

なるほど!go modulesを初期化するときに指定したモジュール名がポイントになるようです。

教えていただいた通り、以下のように初期化を行うことでmodule名/パッケージ名で無事インポートできるようになりました。

$ pwd
/Users/turara/Dev/Go/zenn-first-article
$ go mod init zenn-first-article // module名を指定
go: creating new go.mod: module zenn-first-article
$ cat go.mod
module zenn-first-article // module名がgo.modに記載される

go 1.15
package main

import (
	"fmt"
	"zenn-first-article/zenn" // module名/パッケージ名
)

のぼのぼ📡さん、ありがとうございました!

環境

go version go1.15.2 darwin/amd6

おまけ:Goの公開用パッケージの命名について

パッケージの命名について、はじめて知った面白い視点だったので紹介します。

Discussion