import cycle not allowed (循環参照) について
例えば、
package A 内のどれかのファイルで import b をし、
package B 内のどれかのファイルで import a をすると、
a → b → a → b... となり、
「import cycle not allowed」というエラーが起きる。
これは「循環参照」といって import した先々を繋いでいった場合に、
終わりが来ればエラーは起きないのだけれど、
import の先々でお互いを import していった場合に、
このようなエラーが起きる。
上記だと2つの package だけなので分かりにくいけど、
例えば、
package A 内のどれかのファイルで import b をし、
package B 内のどれかのファイルで import c をし、
package C 内のどれかのファイルで import a をすると、
a → b → c → a → b → c → a... となり、
import 先で循環 (cycle) が起きる。
つまり、
「import cycle not allowed」
「import の循環 (cycle) は許可されてない (not allowed)」
ということになる。
循環参照が起きるパターン
ファイル構成
- /path/to/go/src/psychedelicnekopunch/go-sample
a/
├ A.go
└ A2.go
b/
└ B.go
main.go
main.go
- package a を imoprt して A.Get() を呼ぶ。
- A.Get() 内では return B.Get() をしている。
- B.Get() 内では return A2.Get() をしている。
- A2.Get() 内では return "success" になる。
package main
import (
"fmt"
"psychedelicnekopunch/go-sample/a"
)
func main() {
a := a.NewA()
fmt.Print(a.Get())
}
a/A.go
package a
import (
"psychedelicnekopunch/go-sample/b"
)
type A struct {}
func NewA() *A {
return new(A)
}
func (a *A) Get() string {
b := &b.B{ A2: NewA2() }
return b.Get()
}
b/B.go
- package a を import しているので、循環参照が起きている。
package b
import (
"psychedelicnekopunch/go-sample/a"
)
type B struct {
A2 a.A2
}
func (b *B) Get() string {
return b.A2.Get()
}
a/A2.go
package a
type A2 struct {}
func NewA2() *A2 {
return new(A2)
}
func (a *A2) Get() string {
return "success"
}
解決策1: 循環参照が起きないパターン
ファイル構成
- /path/to/go/src/psychedelicnekopunch/go-sample
- b/A2.go を生成する。
- このファイル内で interface を定義する。
a/
├ A.go
└ A2.go
b/
├ B.go
└ A2.go
main.go
main.go
- ファイル内容変更なし。
a/A.go
- ファイル内容変更なし。
b/B.go
- a/A2.go ではなく、同じパッケージ内の b/A2.go (interface) を定義する。
- package a を import してないので、この時点で循環参照は起きない。
package b
import (
// "psychedelicnekopunch/go-sample/a"
)
type B struct {
// A2 a.A2
A2 A2
}
func (b *B) Get() string {
return b.A2.Get()
}
a/A2.go
- ファイル内容変更なし。
b/A2.go
- interface を定義する。
package b
type A2 interface {
Get() string
}
解決策2: interface がよく分からない方向け
- 循環参照が起きるのであればそれらのファイルを全て同じ package にする。