Imports and exporting symbols

The package declaration is followed by a series of import statements that specify the packages that are needed.

Importing packages that are not used (unless they are ignored) is a compilation error, which is why the Go formatting tool, gofmt, removes unused packages. There are experimental or community tools like goimports (https://godoc.org/golang.org/x/tools/cmd/goimports) or goreturns (https://github.com/sqs/goreturns) that also add missing imports to a Go file. It's important to avoid having circular dependencies because they will not compile.

Since circular dependencies are not allowed, the packages need to be designed differently to other languages. In order to break the circular dependency, it is good practice to export functionalities from a package or replace the dependency with an interface.

Go reduces all the symbol visibility to a binary model – exported and not exported  unlike many other languages, which have intermediate levels. For each package, all the symbols starting with a capital letter are exported, while everything else is used only inside the package. The exported values can also be used by other packages, while the unexported ones can only be used in the package itself.

An exception is made if one of the package path elements is internal (for example, my/package/internal/pdf). This limits itself and its subpackages to be imported only by the nearby packages (for example, my/package). This is useful if there are a lot of unexported symbols and you want to break them down into subpackages, while preventing other packages from using it, making basically private subpackages. Take a look at the following list of internal packages:

  • my/package/internal
  • my/package/internal/numbers
  • my/package/internal/strings

These can only be used by my/package, and cannot be imported by any other package, including my.

The import can have different forms. The standard import form is the complete package name:

import "math/rand"
...
rand.Intn

A named import replaces the package name with a custom name, which must be used when referencing the package:

import r "math/rand"
...
r.Intn

The same package import makes the symbol available with no namespace:

import . "math/rand"
...
Intn

Ignored imports are used to import packages without you having to use them. This makes it possible to execute the init function of the package without referencing the package in your code:

import _ math/rand  
// still executes the rand.init function