Packages and imports
| One directory, one package | |
| Import paths | |
| Alias and dot imports | |
| init order |
One directory, one package
A package is a directory of Go files that share one package clause. The module path in go.mod gives every package a full address, so other files import it by that path instead of by file name.
myshop/
go.mod
math/add.go
main.go
The library file below declares its package and one exported function. Save it as math/add.go so its address becomes the module path plus math.
package math
func Add(a, b int) int {
return a + b
}
Only names starting with a capital letter cross the package border, which is why Add is visible and a helper named add would stay private.
Import paths
An import path names a package, not a file. Standard library paths are short words such as fmt and strings, while your own packages start with the module path, for example example.com/shop/math.
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ToUpper("go"))
fmt.Println(strings.HasPrefix("gopher", "go"))
}
Group imports in one parenthesized block, with standard packages first and external ones after a blank line. The go tool complains about missing and unused imports, so the block always mirrors what the file truly uses.
Alias and dot imports
When two packages export the same name, import one under a short alias and keep the code unambiguous. A single underscore blanks an import used only for setup, and a dot nickname drops the qualifier entirely, so save the dot for small test files.
package main
import (
"fmt"
s "strings"
)
func main() {
shout := s.ToUpper("hello")
fmt.Println(shout)
}
Here strings answers to s, so s.ToUpper reads clearly next to fmt.Println. Prefer meaningful aliases over single letters in large files, where the reader cannot see the import block and the call at once.
init order
Package variables initialize first, then each init function runs, and only then does main start. Every imported package completes its own chain before its importer, so the whole program wakes up from the leaves inward.
package main
import "fmt"
func note(step string) string {
fmt.Println(step)
return step
}
var started = note("package variable ready")
func init() {
fmt.Println("init runs")
}
func main() {
fmt.Println("main runs")
}
package variable ready
init runs
main runs
Keep init small and predictable, because it runs before main and hides work from the reader. Heavy setup belongs in an explicit function that main calls on purpose.
Next: The go toolchain
Article author: Arthur Isaev