Modules and packages
First, a few words about modules and packages would be helpful. A package is a cohesive unit of data types, constants, variables, and functions. You build and test packages, not individual files or modules. When you build a package, the build system collects and also builds all dependent packages. If the package name is main
, building it will result in an executable. You can run the main
package without producing a binary (more specifically, the Go build system first builds the package, produces the binary in a temporary location, and runs it). To use another package, you import it. Modules help with organizing multiple packages and the resolution of package references within a project. A module is simply a collection of packages. If you import a package into your program, the module containing that package will be added to go.mod
, and a checksum of the contents of that module will be added to go.sum
. Modules also help you to manage versions of your programs.
All files of a package are stored under a single directory on the filesystem. Every package has a name declared using the package
directive, shared by all source files in it. The package name usually matches the directory name containing the files, but this is not necessarily so. For example, the main
package is not usually under a directory named main/
. The directory of the package determines the package’s “import path.” You import another package into your current package using the import <importPath>
statement. Once you import a package, you use the names declared in that package using its package name (which is not necessarily the directory name).
A module name points to the location where the module contents are stored in a version control system on the Internet. At the time of writing, this is not a hard-and-fast requirement, so you can actually create module names that do not follow this convention. This should be avoided to prevent potential future incompatibilities with the build system. Your module names should be part of the import paths for the packages of those modules. In particular, module names whose first component (the part before the first /
) does not have .
are reserved for the standard library.
These concepts are illustrated in Figure 1.1.
Figure 1.1 – Modules and packages
- The module name declared in
go.mod
is the repository path where the module can be found. - The import path in
main.go
defines where the imported package can be found. The Go build system will locate the package using this import path, and then it will locate the module containing the package by scanning the parent directories of the package path. Once the module is found, it will be downloaded to the module cache. - The package name defined in the imported module is the package name you use to access the symbols of that package. This can be different from the last component of the import path. In our example, the package name is
example
, but the import path for this package isgithub.com/bserdar/go-recipes-module
. - The
Example
function is located in theexample
package. - The
example
package also imports another package contained in the same module. The build system will identify this package to be part of the same module and resolve the references, using the downloaded version of the module.