0

My code is simple.

Project/
    main.go
    pokemons/
        pokemon.go
    pokeTrainers/
        pokeTrainer.go

I have some Pokemon trainers which are defined like this :

package pokeTrainers

import "../pokemons"

type PokeTrainer struct {
    name        string
    pokemon    []Pokemon
}

And some Pokemon :

package pokemons

import "../pokeTrainers"

type Pokemon struct {
    name            string
    pokeTrainers    PokeTrainer
    }

main package is:

package main

import (
    "fmt"
    "./pokemons"
    "./pokeTrainers"
)

func main() {
    fmt.Printf("ERROR CIRCULAR IMPORT")

As always when I have an error, I copy-paste it on google. I learn what's a circular import and how people fix it with interface to use methods from another package without import it. But in my case, the problem is not to use methods but a real Type defined in another package.

So you will probably say: "Man you are dumb ! You just have to put everything on the same package and it's fine !" Sorry, I come from Java and I would like that my code stays clean. ;)

I saw this link which suggest to use a third party packages ? But you have to imagine that I don't have only pokemon and pokeTrainer, I have many more packages with a type inside and a lot of methods..

What do you think ? How can I fix this error proprelly ? I'm a beginner in Go

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
Titou
  • 64
  • 6
  • 3
    Types that are codependent belong in the same package. Also never use relative import paths. – JimB Feb 20 '18 at 11:54
  • 6
    It is not helpful to program Java in Go. If you want to do it in Go: Do it in Go and stop the "but I want to be it like Java" attitude. – Volker Feb 20 '18 at 11:56
  • 1
    Even in Java, circular dependencies are a sign of a poor design. The compiler just doesn't forbid them. – Adrian Feb 20 '18 at 16:03
  • My guess is that the reason Java allows you to do this is because keywords like `protected` make a difference as to what goes in the package and what doesn't. I don't think the same arguments that can be made for doing this in Java would work for Go based purely on the semantics of each language. – Emil Feb 20 '18 at 18:30

2 Answers2

5

Either use a single package, so no import is needed.

Or designate one of your packages to be a "master", and put "everything" that is needed from both packages into this "master", and so only the other package needs to import "master" by definition (and "master" doesn't need to import the other).

Or you have to create a 3rd package for the stuff that is needed from both, and your 2 current packages only have to import this 3rd common package.

P.S. And don't use relative imports. Always use the complete package path.

icza
  • 389,944
  • 63
  • 907
  • 827
0

I suggest you using interface for Pokemon. Perhaps you will add a several type of a pokemon and PokeTrainer should to train each one.

Example:

poketrainer.go

package pokeTrainers

type IPokemon interface {
    train() error
}

type PokeTrainer struct {
   name        string
   pokemon    []IPokemon
}

pokemon.go

package pokemons

import "github.com/pokemonWorld/pokeTrainers"

type Pikachu struct {
   name   string
   sensei *PokeTrainer
}

func (o *Pikachu) train() error {
   // your code here
}

One extra point of a recommendation - use a pointer of structure but not as a value.

alexey_p
  • 196
  • 7
  • "One extra point of a recommendation - use a pointer of structure but not as a value. " Yeah I'll change that ! Thx for the advice of interfaces but my project is not about pokemons and I don't have many type of pokemon :) – Titou Feb 20 '18 at 22:24