エラー内容
gopls requires a module at the root of your workspace.
You can work with multiple modules by opening each one as a workspace folder.
Improvements to this workflow will be coming soon, and you can learn more here:
https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.go list
gopls が吐き出している上記エラーは、2 つの内容に分かれています。
-
gopls requires ... of your workspace.
- 「プロジェクトのルート・ディレクトリに
go.mod が存在しないため、必要なパッケージが検証できない」という意味
-
You can work with multiple ... go list
- 「プロジェクト内に複数の
go.mod を設置する必要がある(複数の main.go がある)場合は go.work を利用してワークスペースとして定義できます」という意味
今回は、モノリシックなプロジェクトではない(複数の異なるプロジェクトを 1 つのリポジトリで管理するタイプではない)ので、前者のエラー内容が該当します。
原因
gopls が ./bookputGo/ に Go(以下 golang)のコード(main.go)を見つけるも、パッケージ情報(go.mod と go.sum)がプロジェクトのルートにないため、コードを解析する際に必要なモジュールが事前に読み込めずエラーを表示します。
しかし、サブ・ディレクトリに ./bookputGo/go.mod を見つけたため、マルチ・モジュールかもしれないと、二つ目のエラーを表示しています。
対策
bookputGo/go.mod を一階層上のプロジェクトのルートに設置・移動する必要があります。
理由
gopls は静的解析ツール(プログラムをコンパイルせずに、ソースコードを構文解析するタイプ)なので、あらかじめプロジェクトが必要とするパッケージやモジュールを定義したファイル(go.mod もしくは go.work)をプロジェクト・ルートに置いておく必要があります。
つまり、main.go と同じ階層で go mod init ... をせずに、プロジェクトのルート(yarn.lock などと同じ階層)で go mod init github.com/shunsa10/bookput を実行します。
そして go mod tidy すると、サブ・ディレクトリを含むディレクトリをスキャンして、各々のパッケージで import されているモジュールを見つけると go.mod に追記し、その時点のモジュールのバージョンを go.sum に記録します。
go.mod は Node.js でいう package.json と同じ役割をするものです。つまり、そのプロジェクトで利用されるモジュールを定義したファイルです。
そして、go.sum は yarn.lock と同じで、動作確認が取れているモジュール/パッケージのバージョンが記載されたものです。
モジュールとパッケージ
わかりづらいのですが、golang において、他の言語(例えば PHP や Java など)でいうモジュールとパッケージの概念が、最初のうちは感覚的に逆になります(Go に慣れてくると同じものだと気づくのですが)。
-
パッケージとは: 1 つのディレクトリに収まっている Go コードのこと
-
モジュールとは: 上記パッケージを 1 つにまとめたもの(
go.mod 以下にある package ファイル)
特に、main.go のトップには package main と書くものだから、「main パッケージが必要とするモジュールは同じ階層に go.mod として置く」と思い込みがちです。
しかし、go.mod は「そのプロジェクトが必要とするモジュールを定義しているもの」です。
つまり、go get ... で利用できるライブラリのような main.go が存在しないプロジェクトであっても go.mod は存在します。
そのため、golang においては、「パッケージとは、モジュールとして利用できる単位(package main を除く)」と考えるといいかもしれません。