Three structures are there: A(package a)
,B(package b)
,C(package c)
.
B
wants to use functionality of C
and C
wants to use functionality of B
. A
has both B
and C
instances, so that B
can access functionality of C
via A
and vice versa.
I used an interface Ageter
declared in another package i
which has function declaration as GetA() *a.A
Now I am using this interface Ageter
in B
and C
through which I get instance of A
and access functionality of C
and B
respectively.
package a
import (
"fmt"
"basics/importCycleIssue/issueFix/b"
"basics/importCycleIssue/issueFix/c"
)
type A struct {
B *b.B
C *c.C
}
var a = NewA()
func NewA() *A {
a := &A{}
a.B = b.NewB(a)
a.C = c.NewC(a)
return a
}
func GetA() *A{
return a
}
---------------------------------------------------
package b
import (
"fmt"
"basics/importCycleIssue/issueFix/i"
)
type B struct {
o i.Ageter
}
func NewB(o i.Ageter) *B {
b := &B{o: o}
return b
}
func (b *B) UseC() {
fmt.Println("need to use C:",b.o.GetA().C)
}
----------------------------------------------------
package c
import (
"fmt"
"basics/importCycleIssue/issueFix/i"
)
type C struct {
o i.Ageter
}
func NewC(o i.Ageter) *C {
c := &C{o: o}
return c
}
func (c *C) UseB() {
fmt.Println("need to use B:",c.o.GetA().B)
}
----------------------------------------------------
package i
import (
"basics/importCycleIssue/issueFix/a"
)
type Aprinter interface {
PrintA()
}
type Ageter interface {
GetA() *a.A
}
---------------------------------------------------
package main
import (
"basics/importCycleIssue/issueFix/a"
)
func main() {
o := a.NewA()
o.B.UseC()
o.C.UseB()
}
I should be able to use functionality of B
in C
and vice versa.
While building the code I am getting import cycle not allowed
error. import cycle not allowed package main imports basics/importCycleIssue/issueFix/a imports basics/importCycleIssue/issueFix/b imports basics/importCycleIssue/issueFix/i imports basics/importCycleIssue/issueFix/a
Can anyone tell me how to fix this problem?
Thanks.
Go doesn’t allow import cycles to occur. If there are any import cycles detected, it throws a compile time error. Generally import cycles are considered as a bad design.
There are different approaches to solve this, for example you can use same package to describe all these 3 types in different 3 files:
package types
type A struct {
B *b.B
C *c.C
}
type B struct {
o i.Ageter
}
type C struct {
o i.Ageter
}
You're almost there, but I think you might be misunderstanding how you're supposed to use interfaces to fix a cyclic dependency. You've defined interfaces that directly reference the concrete types, so the dependency cycle is still there. Having i
depend on a
doesn't fix the problem, it just extends the cyclic dependency.
Let's get back to your core problem:
B wants to use functionality of C and C wants to use functionality of B. A has both B and C instances, so that B can access functionality of C via A and vice versa.
You need to use your new package i
to define interfaces only. Those interfaces should only reference each other - no references to A, B, or C. B and C should only reference the interface types in i - no references to A, B or C. Because of this, i must define interfaces for the necessary types in all 3 packages. For example:
package i
import (
)
type A interface {
GetB() B
GetC() C
}
type B interface {
UseC()
}
type C interface {
UseB()
}
---------------------------------------------------
package a
import (
"fmt"
"basics/importCycleIssue/issueFix/b"
"basics/importCycleIssue/issueFix/c"
"basics/importCycleIssue/issueFix/i"
)
type A struct {
B *b.B
C *c.C
}
func NewA() *A {
a := &A{}
a.B = b.NewB(a)
a.C = c.NewC(a)
return a
}
// These methods implement i.A and return the i.B and i.C interface types
func (a A) GetB() i.B {
return a.B
}
func (a A) GetC() i.C {
return a.C
}
---------------------------------------------------
package b
import (
"fmt"
"basics/importCycleIssue/issueFix/i"
)
type B struct {
a i.A
}
func NewB(a i.A) *B {
b := &B{a: a}
return b
}
func (b *B) UseC() {
fmt.Println("need to use C:",b.a.GetC())
}
----------------------------------------------------
package c
import (
"fmt"
"basics/importCycleIssue/issueFix/i"
)
type C struct {
a i.A
}
func NewC(a i.A) *C {
c := &C{a: a}
return c
}
func (c *C) UseB() {
fmt.Println("need to use B:",c.a.GetB())
}