【Golang】ローカル自作パッケージを使おうとすると「package XXX/ZZZZ is not in std」になる
はじまり


※当ページはアフィリエイト広告を利用しています。
想定する読者
Go 言語を始めたての初心者
まず、何が起きてるんだ
最近まで、 Python を書いていましたが、処理速度とメモリ節約に関する冒険がしたくなり、 Go を使い始めました。
そこで、自分で書いたローカルパッケージをmain.goなどで使おうとした時の話です。
話題のランタイム環境は、 Go 1.22.2 です。
はい、まずは憎きこのエラー文からです。
main.go:9:3: package mymodule/mypkg is not in std (/usr/local/go/src/mymodule/mypkg)もしくは、 VSCode 上で表示されるこのエラー文。
could not import mymodule/mypkg (no required module provides package "mymodule/mypkg")コイツらを乗り越えて、 Go を実行したい!
まずは結論から。
結論としては、以下のディレクトリ構成で以下のようにファイルを設定すれば出来ました。
ディレクトリ構成:
mymodule|--go.mod|--go.sum|--main.go|--mypkg| |--tools.gomodule mymodule
go 1.22.2
require ( github.com/google/go-github v17.0.0+incompatible golang.org/x/oauth2 v0.19.0)
require github.com/google/go-querystring v1.1.0 // indirectpackage main
import ( "fmt"
"mymodule/mypkg"
"github.com/google/go-github/github" "golang.org/x/oauth2")
// ...略
func main() { fmt.Println(mypkg.Hello())}package my
// ...略
func Hello() string { return "Hello, world!"}そして、内部パッケージを導入する際には、以下の4点に気を付ければ良いのかなと思いました。
- 自作パッケージの中のファイル名は何でも良い:
mypkgディレクトリ内にあるファイル名はtools.goですし、そのファイルのpackage文にmypkgは書いてありません。しかし、プログラムとしては問題なく動きます。ビルドしても動きます。 - 自作パッケージの中に
go.modは不要である: 自作パッケージのディレクトリにgo.modが無ければ、親ディレクトリを見に行きます。モジュール全体で必要な外部パッケージが分からなくなるので、go.modはルートディレクトリだけに置かれるのが良さそうだと思いました。 go.mod内のmoduleの値が重要である: ここのモジュール名から、直下のサブディレクトリを参照していきます。main.goのimport文にはディレクトリ名を書く: 僕の場合はファイル名を書いていて沼りました。
自作パッケージを使用するまでの手順
それでは、細かいところを手順立てていきましょう。
1. パッケージの設定
mypkgディレクトリにあるtools.goファイルでパッケージを定義します。ファイルの先頭に以下のように記述します。
package my
// ...略
func Hello() string { return "Hello, world!"}ここで、package文には、mypkgではなくmyと書きました。外部パッケージとして利用する場合にどうなるかはちょっと分かりませんが、ただ内部で動かす時は問題なく動きます。
2. main.goでのパッケージのインポート
そして、main.goにこんな感じで書きます。
package main
import ( "fmt"
"mymodule/mypkg"
"github.com/google/go-github/github" "golang.org/x/oauth2")
// ...略
func main() { fmt.Println(mypkg.Hello())}そうしたら、必要な外部パッケージのインポートがまだ出来ていないので、go mod initでインストールおよびインポートします。
3. go.modでモジュールを明示する
ここで、go mod initを使うと、このようなメッセージが返ってきますよね。
go: cannot determine module path for source directory /home/username/mymodule (outside GOPATH, module path must be specified)
Example usage: 'go mod init example.com/m' to initialize a v0 or v1 module 'go mod init example.com/m/v2' to initialize a v2 module
Run 'go help mod init' for more information.自分は当初、これはおまじないのようなものだと思っていましたが、ここでgo mod initの引数に渡す文字列がモジュール名になるようです。この部分がとても大事です。
なので、go mod init <モジュール名>を実行して、
go mod init mymoduleすると、こんな感じでメッセージが返ってきます。go.modも作成されます。
go: creating new go.mod: module mymodulego: to add module requirements and sums: go mod tidyしかし、必要なパッケージがまだインストールされていないので、go mod tidyをして必要なパッケージを全て入れます。
go mod tidygo mod tidyをすると、go.modにmain.goの処理に必要なパッケージが列挙されて、未インストールのものはインストールされます。
go.modの中にはこんな感じで記述されているかと思います。
module mymodule
go 1.22.2
require ( github.com/google/go-github v17.0.0+incompatible golang.org/x/oauth2 v0.19.0)
require github.com/google/go-querystring v1.1.0 // indirectここで、go.modには内部パッケージの情報は記されていないことが分かります。
しかし、go.modが存在している状態では、そのパッケージ全体はモジュールモードとなり、module文に記述されている文字列がモジュール名になるわけです。(go.modが存在していないと、GOPATHモードになるみたいです。ちょっと、そのモードで弄る気力は持ち合わせていない。)
モジュールモードでは、このモジュール名から内部パッケージを参照していきます。なので、"mymodule/mypkg"でmypkg内にあるtools.goを参照できるというわけです。
これで動くようになりました!
まとめ
Go 言語でローカルの自作パッケージをインポートする方法を紹介しました。以下にポイントをまとめます。
- 自作パッケージの中のファイル名と
package名は、適当に付けても動くことは動く。 - 自作パッケージの中に
go.modは不要である go.mod内のmoduleの値およびgo mod initの引数が重要である。main.goのimport文にはディレクトリ名を書く。
この内部パッケージのインポートの作業でかなり時間を無駄にしたので、同じように無駄にする人が一人でも減れば嬉しいですね・・・!
プログラミングのお供に
おしまい


以上になります!
記事を共有
この記事が役に立ったなら、ぜひ他の人と共有してください!