SoFunction
Updated on 2025-03-02

2 solutions to Golang's "import cycle not allowed" error

Preface

I believe that many Gophers have encountered the import cycle not allowed problem when writing Golang programs. When I recently studied the go-ethereum source code, I found that defining interface can also solve this problem, and can also solve the situation where even subcontracting cannot be solved, and it is simpler and faster than subcontracting. The following explains the two methods of subcontracting and defining interfaces one by one.

1. Application scenarios

Suppose there are the following usage scenarios:

A is the framework-level structure of the application, containing pointers to submodules B and C in A;

B In order to facilitate the use of other submodules (such as C) functions of the application, the pointer of A is included in its structure;

C To call a method in package A;

2. Code implementation

The procedures are roughly as follows:

package a code is as follows:

package a

import (
 "fmt"

 "/ggq89/mutualdep/b"
 "/ggq89/mutualdep/c"
)

type A struct {
 Pb *
 Pc *
}

func New(ic int) *A {
 a := &A{
 Pc: (ic),
 }

  = (a)

 return a
}

func Printf(v int) {
 ("%v", v)
}

The package b code is as follows:

package b

import (
 "/ggq89/mutualdep/a"
)

type B struct {
 Pa *
}

func New(a *) *B {
 return &B{
 Pa: a,
 }
}

func (b *B) DisplayC() {
 ()
}

The package c code is as follows:

package c

import "/ggq89/mutualdep/a"

type C struct {
 Vc int
}

func New(i int) *C {
 return &C{
 Vc: i,
 }
}

func (c *C) Show() {
 ()
}

package a depends on package b and package c, while package b depends on package a and package c also depend on package a.

The main function code is as follows:

package main

import "/ggq89/mutualdep/a"

func main() {
 a := (3)
 ()
}

An error will be reported during compilation:

import cycle not allowed
package main
    imports /ggq89/mutualdep/a
    imports /ggq89/mutualdep/b
    imports /ggq89/mutualdep/a

3. Define the interface

The problem now is:

A depends on B
B depends on A

For the interdependence problem of A struct and B struct having each other's pointers, you can use the method of defining the interface to solve it. The specific steps are as follows:

Define a interface in package b; convert all the variables and methods used in structure a into methods using interface a; supplement the missing methods in a interface;

After the above steps, the package b code is as follows:

package b

import (
 "/ggq89/mutualdep/c"
)

type B struct {
 Pa a
}

type a interface {
 GetC() *
}

func New(a a) *B {
 return &B{
 Pa:a,
 }
}

func (b *B) DisplayC() {
 ().Show()
}

supplementing possible missing methods in package a;

After processing, the code in package a is as follows:

package a

import (
 "fmt"

 "/ggq89/mutualdep/b"
 "/ggq89/mutualdep/c"
)

type A struct {
 Pb *
 Pc *
}

func New(ic int) *A {
 a := &A{
 Pc:(ic),
 }

  = (a)

 return a
}

func (a *A)GetC() * {
 return 
}

func Printf(v int) {
 ("%v", v)
}

4. Split the package

Compile again, the prompt is as follows:

import cycle not allowed
package main
    imports /ggq89/mutualdep/a
    imports /ggq89/mutualdep/b
    imports /ggq89/mutualdep/c
    imports /ggq89/mutualdep/a

Now is another interdependence problem:

A depends on C
C depends on A

Unlike the previous interdependence, the previous dependency is caused by the A struct and B struct having each other's pointers, which is a hard interdependence;

And here is caused by the method in package c calling the method in package a, which is a soft interdependence;

  • This interdependence can be solved by splitting the method into another package; during the process of splitting the package, the method of the structure may be converted into a normal function;

Introduce package f and migrate the method to f:

package f

import "fmt"

func Printf(v int) {
 ("%v", v)
}

After the method is moved to package f, the code of package a is as follows:

package a

import (
 "/ggq89/mutualdep/b"
 "/ggq89/mutualdep/c"
)

type A struct {
 Pb *
 Pc *
}

func New(ic int) *A {
 a := &A{
 Pc: (ic),
 }

  = (a)

 return a
}

func (a *A) GetC() * {
 return 
}

package c is then changed to calling package f, and its code is as follows:

package c

import (
 "/ggq89/mutualdep/a/f"
)

type C struct {
 Vc int
}

func New(i int) *C {
 return &C{
 Vc: i,
 }
}

func (c *C) Show() {
 ()
}

Now the dependency relationship is as follows:

A depends on B and C
B depends on C
C depends on F

At this point, both package interdependencies are resolved.

5. Summary

For soft interdependence, subcontracting can be solved by using subcontracting methods. The interdependence caused by some functions can only be solved by subcontracting; subcontracting can refine the functions of the package;

Hard interdependence can only be solved by defining interfaces; defining interfaces can improve the independence of packages, and also improve the difficulty of tracking code call relationships;

Reference article:

  • golang does not allow loop import problem ("import cycle not allowed"):https:///article/
  • Golang's idea to solve the import cycle not allowed:https:///article/

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.