intermediate15 min

Packages and Exported Identifiers

How Go organizes code into packages, and its capitalization-based visibility rule.

What you'll learn

  • Explain how Go groups files into packages
  • State Go's rule for exported (public) vs unexported (private) identifiers
  • Read a Go import path and identify the package it refers to

Explanation

Every Go source file belongs to exactly one package, declared at the top of the file (package main, package util, and so on). Every .go file in the same directory must declare the same package name -- a package is really a directory's worth of files sharing one namespace.

Go's visibility rule is refreshingly simple and has no dedicated keyword: an identifier (a function, type, variable, or struct field) whose name starts with an uppercase letter is exported (visible outside its package); one starting lowercase is unexported (package-private). func Add(...) is callable from other packages; func add(...) is not.

A Go module (declared in a go.mod file) is a collection of related packages versioned and distributed together -- when you import "github.com/someuser/somemodule/somepackage", you're pulling in one package from someone else's module.

This capitalization convention means you can often tell a lot about a package's public API just by scanning for capitalized names, without needing separate public/private keywords cluttering every declaration.

Guided lab

Predict: Exported vs unexported identifiers

GoNot executed
This lab does not run in your browser or on VisaSparkSchools's servers. Read the code, predict what it does, then reveal the real expected output.

This shows two files from the same package (comments mark the file boundary). Predict what main.go prints, and note the one line that would NOT compile if uncommented.

// file: util/util.go
package util

func Double(n int) int {
	return double(n) * 2
}

func double(n int) int {
	return n * 2
}

// file: main.go
package main

import (
	"fmt"
	"example.com/app/util"
)

func main() {
	fmt.Println(util.Double(3))
	// fmt.Println(util.double(3)) // would NOT compile: double is unexported
}

Stuck? Get a hint.

Common mistakes

  • Trying to call a lowercase (unexported) function from a different package and being confused by the compile error.
  • Putting files with different `package` declarations in the same directory -- every file in one directory must share the same package name.
  • Confusing a Go module (versioned collection of packages, from go.mod) with a single package (one directory's worth of files).

Knowledge check

Knowledge check

1. In Go, what makes an identifier exported (visible outside its package)?
2. Can two files in the same directory declare different package names?
3. What is a Go module?

Takeaway

Capitalize a name to export it outside its package; lowercase keeps it package-private -- no separate keyword needed.

Summary

Files sharing a directory form one package; capitalization alone determines export visibility; a module (go.mod) versions a collection of packages.

References

Your notes

Notes save automatically.

Finished this lesson?

Mark it complete to track your progress and schedule a future review.

Next: Testing with go test