I have a project with several modules in Go. I am having problem with circular imports because of the scenario below:
A module Game contains a struct with the current Game state. Another module (Modifier) is doing some game specific stuff and calculations and therefore modifies the game state. Because of this, Modifier will need the struct Game, but not any methods from Game. Modifier is called from Game and here we have the circular import.
Game initiates Modifier
Modifier needs Game struct
It seems to me that this is a common scenario, so I wonder how I should solve it in the best way. My solution would be to create a third module "Structs" which just contains all the structs for the whole application. Is this a good solution?
If the error occurs due to a circular dependency, it can be resolved by moving the imported classes to a third file and importing them from this file. If the error occurs due to a misspelled name, the name of the class in the Python file should be verified and corrected.
Generally, the Python Circular Import problem occurs when you accidentally name your working file the same as the module name and those modules depend on each other. This way the python opens the same file which causes a circular loop and eventually throws an error.
A circular dependency is when one of your modules imports another modules, which directly or via other modules imports the first module. Examples: Direct reference: A -> B -> A. // a.js import { b } from './b.js' // b.js import { a } from './a.js'
With the 3rd package option:
yourgame/
state/
state.go
modifier/
modifier.go
main.go
main.go
would glue the two components together:
import "yourgame/state"
import "yourgame/modifier"
type Game struct {
state state.State
modifier modifier.Modifier
}
func main() {
// something like:
var game Game
game.modifier.Modify(game.state)
}
This approach is probably too tightly coupled though. Rather than manipulating an essentially global state object, I would try to slice up the data into just what you need for the modifier.
Reasoning in the abstract is hard, so here's a concrete example of what I mean. In your game:
type Object struct {
ID, X, Y int
// more data here
}
type Game struct {
Objects map[int]*Object
}
In your "modifier", let's suppose we had an AI module that moves an object. If all he cares about is the position of a single object you can create an interface:
// in yourgame/modifier
type Object interface {
GetCoordinates() (int, int)
SetCoordinates(int, int)
}
type Modifier struct {}
func (m *Modifier) Update(obj Object) { }
Then we just have to add those methods to our original Object:
type (obj *Object) GetCoordinates() (int, int) {
return obj.X, obj.Y
}
type (obj *Object) SetCoordinates(x, y int) {
obj.X, obj.Y = x, y
}
And now you can pass objects to your modifier without needing a cyclic dependency.
Now if it turns out your "modifier" interface ends up looking almost exactly the same as your game object, then a 3rd package of structs is probably reasonable so you aren't always repeating yourself. For an example consider net/url
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With