I like splitting my modules/packages into many files (e.g. a bigger function file and a coupled helpers file). Now a module can have many bigger functions as it grows. Let's say my modules/packages each consist of around 30 files.
When I started working with Go a few days ago, I was a bit confused about the module pattern. I have a JavaScript (ES6+) background. After some research, I found you could build packages consisting of multiple files by running the following command go build ./...
. This worked out pretty well, until my package consisted of about 10 files. All of a sudden I saw errors about functions being undefined. Meanwhile those functions where clearly defined in the src of the module/package (and properly capitalized).
My gut feeling says that this is because of the build order. Say we have 2 files 'a.go' and 'b.go'. file 'a.go' got a reference to a function in file 'b.go'. When file 'a.go' is build before 'b.go', an undefined error appears. My second gut feeling is that file 'a.go' contains a reference to a function inside file 'b.go' and the same vice-versa. So file 'b.go' also has reference to a function in file 'a.go'.
You can have as many .go
files in a single directory as you'd like.
A Go package consists of all of the .go
files in a single directory. Each .go
file in a single directory should have the same package foo
declaration as the other .go
files in the same directory.
Your source code imports code from another package (another directory) via an import path supplied in an import statement such as import "github.com/my/repo/pkg1"
.
To build a package, you can cd
to the directory and issue go build .
(where .
means build all the files in the current directory, or you can also just issue go build
in that directory without any arguments because the default is .
).
Code within the same package (the same directory) can reference code in other files in the same package (same directory) without needing to import the other files, and without needing the symbols to be exported (uppercase first character).
It is well worth the time to read "How to Write Go Code", which includes an overview of these concepts, including:
Go programmers typically keep all their Go code in a single workspace.
- A workspace contains many version control repositories (managed by Git, for example).
- Each repository contains one or more packages.
- Each package consists of one or more Go source files in a single directory.
- The path to a package's directory determines its import path.
and a bit later it describes the relationship between "workspace" and GOPATH:
The GOPATH environment variable specifies the location of your workspace. It defaults to a directory named go inside your home directory, so $HOME/go on Unix, $home/go on Plan 9, and %USERPROFILE%\go (usually C:\Users\YourName\go) on Windows.
Regarding your more specific concerns:
Splitting a single package into multiple (many) files gives undefined error on go build ./
Splitting a package across multiple individual .go
files in the same directory (same package) should not cause a problem in and of itself, but of course it needs to be done properly (e.g., all .go
files in the same directory (same package) need to have the same package foo
declaration near the top; files in the same directory should not attempt to use import
statements to import other files in the same directory; etc.).
My gut feeling says that this is because of the build order.
Build order shouldn't matter here.
My second gut feeling is that file 'a.go' contains a reference to a function inside file 'b.go' and the same vice-versa. So file 'b.go' also has reference to a function in file 'a.go'.
This is fine if a.go
and b.go
are in the same package (the same directory).
On the other hand, this is not allowed if a.go
and b.go
are in the different packages (different directories). This is because Go does not allow circular dependencies at the package level. If this is the problem, the simplest solution is to move a.go
and b.go
into the same directory, or refactor to introduce a third package to break the cycle so that a
and b
can both depend on the third package, or use interfaces, or other possible solutions, but given you say you are new to Go, the simplest solution might be best while you are learning.