First off, the spec provides an example of how to reference a symbol in an imported package, using different import alias options. I’ve already provided my own examples earlier, and it’s pretty straight forward, so we’ll just breeze through this part.
Import declarations
…
Consider a compiled a package containing the package clause
package math
, which exportsfunction Sin
, and installed the compiled package in the file identified by"lib/math"
. This table illustrates howSin
is accessed in files that import the package after the various types of import declaration.Import declaration Local name of Sin import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin
Then we get to a juicy bit. Or maybe an infuriating bit.
An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers.
Some languages do allow circular imports, at least indirectly. That is to say, something like this might be possible in some languages, but isn’t in Go:
In file github.com/project/foo/foo.go
:
package foo
import "github.com/project/bar"
And in file github.com/project/bar/bar.go
:
package bar
import "github.com/project/foo"
But what if you want a circular import?
Well, you can’t. Simple as that. Ha.
But more seriously, let’s consider a couple alternatives.
-
First, and most important, try to find a different way to organize your project, so that you don’t need a circular import. Precisely 99.8% of the time (give or take 23.32%), circular imports are the result of poor design. Looking at the solution differently will often reveal a different way to organize your project. You may need to merge some packages, or split a package into different parts. There aren’t really any easy, one-size-fits all solutions here. It takes practice.
-
There is one
neatugly trick you can use, to get around this restriction in go. Use it sparingly! And that is to use the ‘registry’ pattern. It’s used in the standard library in a few places, it will be the topic of tomorrow’s email. So stay tuned!
Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)