Course outline

Go / Basic: Values and Program Contracts / Lesson 1

Tooling, Modules, and the Program Model

Follow a Go program from package source to an executable, and record language and toolchain choices explicitly.

About 5 min readContent reviewed
On this page

Lesson goals

  • Distinguish a module, package, and command.
  • Explain main, imports, formatting, and build checks.
  • Read go.mod without confusing it with an exact toolchain lock.

A command is a package with an entry point

A source file begins with a package declaration. Files in one directory usually form one package; a command uses package main and defines func main(). Imported packages provide named interfaces, and the compiler rejects unused imports. Go source is compiled before execution even when go run makes the build step feel invisible.

The first program imports fmt and calls Println, which separates arguments with spaces and ends the line. main returns no value. Returning normally ends that goroutine; returning from main terminates the program, so later lessons must wait for background work explicitly rather than relying on it surviving.

go A complete command
package main

import "fmt"

func main() {
	fmt.Println("Go", "ready")
}
Expected output
Go ready

The command has one entry point and writes a deterministic line.

A module groups versioned packages

A module is a collection of packages released together. Its root contains go.mod, whose module directive defines the import-path prefix. A local learning module can use an example domain without contacting it. Standard-library imports such as fmt do not require downloading third-party modules. Keep each independent demonstration in its own temporary module to avoid duplicate main definitions.

The go directive specifies a minimum Go version and influences language semantics for packages in the module. A toolchain directive can influence tool selection, and automatic selection may download a toolchain. It is not enough to say “my machine has Go”; record go version, the module directives, and relevant environment settings.

Keep a small reproducible workflow

go fmt formats packages using the standard formatter; go build checks and builds the selected packages; go test runs package tests. A successful build proves type and syntax acceptance, not correct behavior for every input. Run these tools from the intended module directory and inspect the first relevant diagnostic rather than editing around later cascading messages.

For isolated standard-library examples, an offline configuration can disable module proxies and automatic toolchain downloads after a suitable compiler is installed. That is a validation convenience, not a universal project policy. Real dependency updates require deliberate retrieval, review, and reproducible version records rather than silently depending on whatever happens to be cached.

Trace a value through full statements

A variable is a named location holding a value of its declared type. The short declaration := introduces a local variable when its rules are satisfied; = assigns to an existing one. In the next program count starts at two and is then replaced by five. The call observes the result of that completed assignment.

This trace uses no assumptions about stack addresses, machine registers, or scheduling. Go implementations decide storage placement, and later compiler optimizations may remove a physical variable entirely. Explain behavior from the language contract and observable effects rather than claiming that every source line corresponds to one processor instruction.

go Observe a completed assignment
package main

import "fmt"

func main() {
	count := 2
	count = count + 3
	fmt.Printf("count=%d\n", count)
}
Expected output
count=5

The integer value becomes five before the formatting call reads it.

Separate a baseline from the latest release

This course declares Go 1.22 language semantics, including the loop-variable change introduced there. Official documentation may describe a newer release; an API marked as added later must not be assumed available in a Go 1.22 project. Check the version annotation and the project’s actual compatibility requirements before copying a convenient new helper.

When reporting a failure, include the minimal source, exact command, module directives, toolchain version, input, and expected versus actual output. A stale executable or a command run in another module can make a correct edit appear ineffective. Reproduce in a clean temporary directory before drawing conclusions about the language.

Common errors and fixes

An imported package is rejected as unused.

Why it happens
No remaining expression refers to that import.
How to fix it
Remove the unused import or use its intended interface.
Prevent it next time
Let the formatter and build checks run after edits.

Two demonstrations cannot build together.

Why it happens
The same package contains multiple main definitions.
How to fix it
Place independent examples in separate temporary directories.
Prevent it next time
Treat each complete example as its own command.

A new helper is unavailable despite valid syntax.

Why it happens
The selected toolchain or library predates the API.
How to fix it
Use a baseline-compatible operation or deliberately update the project requirement.
Prevent it next time
Check official added-in-version annotations.

Check your understanding

1. Predict the second program after initializing count to four and adding seven. Identify which facts determine the output.

Show worked solution

The initializer stores four, then the assignment computes eleven and replaces count. Printf writes count=11 followed by a newline. The result follows from integer arithmetic on small representable values and statement order. It does not depend on a guessed address or compiler optimization level. The declaration still introduces one local int.

2. Explain why a go 1.22 directive alone does not record every fact needed to reproduce a build.

Show worked solution

It records a language/minimum-version requirement, while the selected compiler may be newer. Dependencies, go.sum, workspace settings, build tags, platform settings, and toolchain selection can also affect the build. Record those relevant inputs and run the same package set. For this standard-library-only example, a recorded compiler plus a clean small module keeps the reproduction especially simple.

Key takeaways

  • A command, package, and module are different boundaries.
  • Record language semantics and the actual toolchain separately.
  • A reproducible example includes source, build context, input, and an explicit expected result.

Official references