Go で「import cycle not allowed」が解決できない
Go はパッケージ同士が直接・間接に循環参照することを禁止している。
共通部分を第3のパッケージへ切り出すか、依存の向きをインターフェースで逆転させて循環を断ち切る。
#go#import#package#cycle
公開:
要約
import cycle not allowed は、Go のパッケージが互いを直接または間接に import し合う「循環参照」になっているときのコンパイルエラーです。
Go 言語仕様はパッケージの循環 import を認めていません。
これは設計上の制約で、回避ではなく依存関係そのものを一方向に整理して解消します。
典型的には、共通部分を別パッケージに切り出すか、インターフェースで依存の向きを逆転させます。
package myapp/service
imports myapp/repo
imports myapp/service: import cycle not allowedよくある原因
- 相互参照:
serviceがrepoを、repoがserviceを import している。 - 共通型の置き場所: 両方が使う型を一方のパッケージに置いたため、もう一方がそれを取りに行って循環する。
- ユーティリティの逆流: 「便利関数」パッケージが、本来上位であるはずのパッケージを import している。
- 場所ベースの分割: 責務ではなくファイルの置き場所でパッケージを切ったため、依存が双方向になっている。
解決策
1. 共通部分を第3のパッケージへ切り出す
A と B が共通で必要とする型・定数・インターフェースを model のような独立パッケージに移し、A も B も model を import する形にします。
依存の矢印が model に向かう一方向になり、循環が消えます。
変更前: service ⇄ repo
変更後: service → model ← repo2. インターフェースで依存を逆転させる
下位(repo)が上位(service)の型を直接使いたい場合は、repo 側に必要な振る舞いをインターフェースとして定義し、service がそれを実装します。
下位は上位を import しなくて済みます(依存性逆転)。
// repo パッケージ側でインターフェースを定義し、service を import しない
type Notifier interface {
Notify(msg string) error
}3. 統合・可視化で見直す
分ける必然性が薄ければ 1 パッケージにまとめるのも有効です。
複雑な依存は go list -deps ./... などで可視化し、どの辺が循環しているかを特定してから断ち切ります。