7

I am developing a go package, which is a little bit complex and thus I want to organize the source code into multiple directories.

However, I don't want the users of the package to have to use too long imports. Anyways, the internal structure of the package isn't their concern.

Thus, my package structure looks so:

subDir1
  subSubDir1
  subSubDir2
subDir2
  subSubDir3

...and so on. All of them have their exported calls.

I would like to avoid that my users have to import

import (
  "mypackage/subDir1"
  "mypackage/subDir1/subSubDir2"
)

...and so on.

I only want, if they want to use an exported function from my package, they should have access all of them by simply importing mypackage.

I tried that I declare package mypackage in all of the .go files. Thus, I had source files in different directories, but with the same package declaration.

In this case, the problem what I've confronted was that I simply couldn't import multiple directories from the same package. It said:

./src1.go:6:15: error: redefinition of ‘mypackage’
   "mypackage/mysubdir1"
               ^
./src1.go:4:10: note: previous definition of ‘mypackage’ was here
   "mypackage"
          ^
./src1.go:5:15: error: redefinition of ‘mypackage’
   "mypackage/mysubdir2"
               ^
./src1.go:4:10: note: previous definition of ‘mypackage’ was here
   "mypackage"
          ^

Is it somehow possible?

peterh
  • 11,875
  • 18
  • 85
  • 108

3 Answers3

19

You should not do this in any case, as the language spec allows a compiler implementation to reject such constructs. Quoting from Spec: Package clause:

A set of files sharing the same PackageName form the implementation of a package. An implementation may require that all source files for a package inhabit the same directory.

Instead "structure" your file names to mimic the folder structure; e.g. instead of files of

foo/foo1.go
foo/bar/bar1.go
foo/bar/bar2.go

You could simply use:

foo/foo1.go
foo/bar-bar1.go
foo/bar-bar2.go

Also if your package is so big that you would need multiple folders to even "host" the files of the package implementation, you should really consider not implementing it as a single package, but break it into multiple packages.

Also note that Go 1.5 introduced internal packages. If you create a special internal subfolder inside your package folder, you may create any number of subpackages inside that (even using multiple levels). Your package will be able to import and use them (or to be more precise all packages rooted at your package folder), but no one else outside will be able to do so, it would be a compile time error.

E.g. you may create a foo package, have a foo/foo.go file, and foo/internal/bar package. foo will be able to import foo/internal/bar, but e.g. boo won't. Also foo/baz will also be able to import and use foo/internal/bar because it's rooted at foo/.

So you may use internal packages to break down your big package into smaller ones, effectively grouping your source files into multiple folders. Only thing you have to pay attention to is to put everything your package wants to export into the package and not into the internal packages (as those are not importable / visible from the "outside").

icza
  • 389,944
  • 63
  • 907
  • 827
  • I liked this answer, but I really wanted to hate it. Coming from the java world, it's hard not to instinctively want to divide your source up logically into multiple folders. :D – Arlo Guthrie Sep 24 '20 at 18:22
  • 1
    @ArloGuthrie But you can divide your source into multiple folders, that's standard, they just can't be part of the same package. You also have packages in Java too, in different folders. – icza Sep 25 '20 at 07:10
  • java.util is a package. under it are any number of "folders" ... collections, etc. I'm a serious newbie with golang, but it seems that if you want to write an API you really need to stuff everything into one folder so that the user only needs to import one package, otherwise you get circular dependency issues. am I understanding golang package structure incorrectly? – Arlo Guthrie Sep 28 '20 at 12:34
  • @ArloGuthrie Yes, it's correct that files of a package must be in a single folder. But you are not limited to use only a single package. E.g. the standard lib has an `image` package with several others for image types (e.g. `image/jpeg`), and some parts in differnet packages, e.g. `image/color`, `image/draw` etc. There are techniques to resolve cyclic dependencies, see [Registering packages in Go without cyclic dependency](https://stackoverflow.com/questions/29271440/registering-packages-in-go-without-cyclic-dependency/29272910#29272910). And there's also the mentioned internal packages. – icza Sep 28 '20 at 12:49
  • 1
    I don't see a limitation that's not solvable with Go's package system. They're just not a one-to-one equivalent to Java's packages. It's a different language with different rules and principles. Developing in Go is not Developing in Java. – icza Sep 28 '20 at 12:50
0

Inside your package source code, you have to differentiate your source directories by renamed imports. You can declare the same package mypackage in all of your source files (even if they are in different directories).

However, while you import them, you should give an induvidual names to the directories. In your source src1.go, import the other directories on this way:

import (
  "mypackage"
  submodule1 "mypackage/mySubDir"
)

And you will be able to reach the API defined in "mypackage" as mypackage.AnyThing(), and the API defined in mySubDir as submodule1.AnyThing().

The external world (i.e. the users of your package) will see all exported entities in myPackage.AnyThing().

Avoid namespace collisions. And use better understable, intuitive naming as in the example.

peterh
  • 11,875
  • 18
  • 85
  • 108
0

Yes, this is doable without any problems, just invoke the Go compiler by hand, that is not via the go tool.

But the best advice is: Don't do that. It's ugly and unnecessarily complicated. Just design your package properly.

Addendum (because the real intention of this answer seems to get lost sometimes, maybe because irony is too subtle): Don't do that!! This is an incredible stupid idea! Stop fighting the tools! Everybody will rightfully hate you if you do that! Nobody will understand your code or be able to compile it! Just because something is doable in theory doesn't mean this is a sensible idea in any way. Not even for "learning purpose"! You probably even don't know how to invoke the Go compiler by hand and if you figure it out it will be a major pita.

Volker
  • 40,468
  • 7
  • 81
  • 87