Packages

Every Go file names the package it belongs to; one directory is one package, and declaration order inside it does not matter.

Syntaxpackage name // every file in one directory declares the same package name

A package is one directory of Go files, compiled together as a unit. Every file starts with a package clause that names it, like package main. Packages exist so a program can be split into parts, and so those parts can be reused.

main is the one special name. A package called main that holds a function called main builds into a program you can run. Every other package builds library code for other packages to import.

Importing

An import declaration names the import path of the package you want. For the standard library that path is short, such as strings. For your own code it is your module path plus the directory, such as example.com/app/store. You then reach a name inside the package by writing the package name, a dot, and the name: strings.ToUpper. That form is called a qualified identifier.

The package name is usually the last element of the path, but the package clause decides. net/http declares package http. math/rand/v2 declares package rand.

Two ways to write imports

These are the same thing. One block with several paths is shorthand for several separate import lines.

import (
	"fmt"
	"strings"
)

import "fmt"
import "strings"

Order does not matter

Inside a package, declaration order is free. A function in one file may call a function declared further down the file, or in another file of the same directory. There are no forward declarations and no header files, so split files by subject.

Example

Example · go
// Package main builds a program. The function main is where it starts.
package main

import (
	"fmt"     // printing
	"strings" // text helpers
)

func main() {
	// strings.TrimSpace and strings.ToUpper are exported names
	// inside the strings package, reached through a qualified identifier.
	name := strings.TrimSpace("  ada  ")
	fmt.Println("hello,", strings.ToUpper(name))
}

// Output:
// hello, ADA

When to use it

  • Splitting a single long main.go into several files without changing how it builds.
  • Working out what to type after an import path you copied from documentation.
  • Reading an unfamiliar project and knowing which directory a name like store.Load comes from.

More examples

Two files, one package

Two files in the same directory, both declaring package main, form one package. main.go calls a function from greet.go without importing anything, because they are the same package. Reach for this as soon as one file gets long: splitting by subject costs nothing and changes no behaviour.

Example · go
// greet.go
package main

import "strings"

// greeting is declared in this file but used in main.go.
// No forward declaration is needed, in either direction.
func greeting(name string) string {
	return "hello, " + strings.ToUpper(name)
}

// main.go
package main

import "fmt"

func main() {
	fmt.Println(greeting("ada"))
}

// Output:
// hello, ADA

The package name is not always the last path element

Shows why you read the package's documentation for its name rather than guessing from the path. Version suffixes like /v2 are part of the import path only. You hit this the first time you import a module whose directory and package names differ.

Example · go
package main

import (
	"net/http"    // declares: package http
	"math/rand/v2" // declares: package rand
)

func main() {
	// The path is net/http, the name to write is http.
	var c http.Client
	_ = c

	// The path ends in v2, but the name is still rand.
	var r *rand.Rand
	_ = r
}

Renaming an import

An import may be given a local name by putting it before the path. Use it when two imports would otherwise have the same package name, or when a package name is too vague to read well in your file. The name is local to the one file that declares it.

Example · go
package main

import (
	"fmt"

	// Longhand: give this import a different local name.
	mrand "math/rand/v2"
)

func main() {
	// The local name replaces the package name everywhere in this file.
	fmt.Println(mrand.IntN(1) == 0) // IntN(1) can only return 0
}

// Output:
// true

Discussion

  • Be the first to comment on this lesson.