web-dev-qa-db-ja.com

Goモジュールを使用してパッケージのローカルコードを整理する

main.goの外でGoモジュール(goバージョン> = 1.11)を使用する場合、$GOPATHからローカルパッケージにコードを分解する方法が見つかりません。

go.modに含める必要がある外部依存関係をインポートしていません。このGoモジュールのソースコードをローカルに整理しようとしています。

ファイルmain.go

package main

// this import does not work
import "./stuff"

func main() {
    stuff.PrintBaz()
}

ファイル./stuff/bar.go(ローカルパッケージを装ったもの):

package stuff

import "log"

type Bar struct {
    Baz int
}

func PrintBaz() {
    baz := Bar{42}
    log.Printf("Bar struct: %v", baz)
}

ファイルgo.mod(コマンドgo mod init foo):

module foo

go 1.12

go run main.goを実行する場合:

  • import "./stuff"の場合、build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuffが表示されます。
  • import "stuff"の場合、build command-line-arguments: cannot load stuff: cannot find module providing package stuffが表示されます。
  • パッケージエイリアスでimport stuff "./stuff"を使用すると、build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuffが再び表示されます。

ローカルモジュールをgoモジュールで動作させる方法が見つかりません。

  • 上記のコードの何が問題になっていますか?
  • Goモジュールで定義されたプロジェクト(ファイルgo.mod)内の他のGoコードにローカルパッケージをインポートするにはどうすればよいですか?
18
TPPZ

最初に、プロジェクトの名前を選択し、それをgo.modファイルに書き込む必要があります。この名前は、プロジェクトのルートディレクトリに属しています。作成する新しいパッケージはそれぞれ独自のサブディレクトリ内に配置する必要があり、その名前はディレクトリ名と一致する必要があります。

go.mod:

module myprojectname

または(推奨される方法、詳細については、@ typical182の 下の回答 を参照してください)

module github.com/myname/myproject

次に、プロジェクトのパッケージを次のようにインポートします。

import myprojectname/stuff

または

import github.com/myname/myproject/stuff

パッケージstuffのファイルは、プロジェクトのstuffディレクトリ内に配置する必要があります。これらのファイルには好きな名前を付けます。

また、より深いプロジェクト構造を作成することも可能です。たとえば、ソースコードファイルを他のファイル(アプリ構成、Dockerファイル、静的ファイルなど)から分離することにしました。 stuffディレクトリをpkg内に移動しましょう。pkg/stuff内のすべてのgoファイルには、まだstuffパッケージ名が付いています。スタッフパッケージをインポートするには、次のように記述します。

import myprojectname/pkg/stuff

github.com/myuser/myproject/pkg/db/provider/postgresqlのように、階層内にさらにレベルを作成することを妨げるものはありません。ここで、

  • github.com/myuser/myproject-プロジェクト名。
  • postgresql-パッケージ名。
  • pkg/db/provider/postgresql-プロジェクトのルートに対するパッケージの相対パス。

Goモジュールの詳細については、こちらをご覧ください。 https://github.com/golang/go/wiki/Modules

このリポジトリをチェックして、プロジェクトの編成で使用されるさまざまなパターンに関する有用な情報を取得してください。 https://github.com/golang-standards/project-layoutpkgディレクトリ内に移動すると構造内でpkgディレクトリを使用しているオープンソースプロジェクトを見つけます。

20
Vadim Ashikhman

モジュール構造

最も一般的で簡単なアプローチは次のとおりです。

  • リポジトリごとに単一の_go.mod_を使用し、
  • 単一の_go.mod_ファイルをリポジトリルートに配置し、
  • _go.mod_ のmodule行で宣言されたモジュールパスとしてリポジトリ名を使用します
    • カスタムインポートパス のような_me.io/mymod_などのVCSホストベースのインポートパスを使用する場合は、リポジトリ名の代わりにカスタムインポートパスを使用します_go.mod_)で.

たとえば、リポが_github.com/my/repo_の場合、単一の_go.mod_をリポルートに配置し、最初の行を_module github.com/my/repo_とします。これは、リポジトリルートにcd 'して_go mod init github.com/my/repo_を実行することで作成できます。

これに従うことで、モジュールを使用してハッピーパスを維持でき、複数の微妙な問題を回避できます。

Russ Coxが #26664 にコメントしました:

パワーユーザーを除くすべてのユーザーは、1つのリポジトリ= 1つのモジュールという通常の規則を採用する必要があります。リポジトリcanに複数のモジュールが含まれていることは、コードストレージオプションの長期的な進化にとって重要ですが、ほとんどの場合、デフォルトで実行する必要はありません。

"Multi-module Repositories" FAQモジュールwikiのセクション)に、マルチモジュールリポジトリに関する詳細があります。このセクションは、上記の推奨事項を回避することを検討している人は、その全体を読む必要があります。

モジュール内でのパッケージの配置

_go.mod_を設定すると、パッケージをディレクトリに配置できますが、_go.mod_を含むディレクトリの下のディレクトリと、_go.mod_を含むディレクトリに収まるように見えます。コードをパッケージに配置する方法に関する3つの優れた記事:

これらの記事はモジュールの導入以前の古典ですが、それらの哲学は、モジュール内でパッケージを配置する方法にも適用されます。

同じモジュール内の他のパッケージのインポート

モジュールを含む別のパッケージをインポートするときは、常にモジュールパスを含むフルパスを使用します。これは、同じモジュールに別のパッケージをインポートする場合にも当てはまります。たとえば、モジュールが_go.mod_でモジュールのアイデンティティをモジュール_github.com/my/repo_として宣言し、次のような組織の場合:

_repo/
├── go.mod      <<<<< Note go.mod is located in repo root
├── pkg1
│   └── pkg1.go
└── pkg2
    └── pkg1.go
_

次に、_pkg1_は、ピアパッケージを_import "github.com/my/repo/pkg2"_としてインポートします。 _import "../pkg2"_や_import "./subpkg"_のような相対インポートパスは使用できないできないことに注意してください。 (これは、OPが上記の_import "./stuff"_でヒットしたものの一部です)。

モジュールvsリポジトリvsパッケージvsインポートパス

Goモジュールは、1つのユニットとして一緒にバージョン管理される、関連するGoパッケージのコレクションです。モジュールは正確な依存関係の要件を記録し、再現可能なビルドを作成します。

リポジトリ、モジュール、パッケージ間の関係の要約:

  • repositoryには、1つ以上のGomodulesが含まれています(ほとんどの場合、リポジトリルート内の正確に1つのモジュール)。
  • 各モジュールには、1つ以上のGopackagesが含まれています。
  • 各パッケージは、1つ以上のGosource filesで構成され、これらはすべてsingle directoryにあります。
  • ソースコードに移動:
    • _package foo_ステートメントで独自のパッケージを宣言します。
    • 同じパッケージ内の他のGoソースコードに自動的にアクセスできます。
    • _import "github.com/my/repo/pkg1"_などのインポートステートメントで指定されたimport pathを介して別のパッケージからコードをインポートします。インポートパスは、そのパッケージが同じモジュールにあるか別のモジュールにあるかに関係なく、常にそのパッケージのモジュールパスで始まります。
22
typical182