← Go, End to End

Go, End to End

The Absolute Basics

Every Go program starts life as a package. The file that produces a runnable binary declares package main and defines a func main() with no parameters and no return value. That's the entire entry-point contract, nothing more to configure.

go · live, editable, runnable

Three commands cover almost everything you'll do day to day. go run main.go compiles and runs in one step, throwing away the binary afterward, good for quick iteration. go build compiles into a binary in the current directory and leaves it there. go install does the same but places the binary in your GOPATH/bin (or GOBIN), so it ends up on your PATH if that's configured, useful for tools you want available everywhere.

Imports

An import block lists the packages a file depends on. The standard library path is just the package name for single-word packages (fmt, os, strings) and a slash-separated path for nested ones (net/http, encoding/json). Go is strict about this: importing a package and not using it is a compile error, not a warning. There's no such thing as an unused import lingering in committed code.

go
import (
	"fmt"
	"os"
	"strings"
)

No semicolons, mandatory braces

Go statements don't end in semicolons in the source you write. The compiler inserts them automatically based on a simple rule (a semicolon gets added at the end of a line if the last token could end a statement), which is also why the opening brace of a block has to be on the same line as whatever it belongs to. Put it on the next line and the automatic semicolon insertion breaks your function.

go · live, editable, runnable

Putting { on its own line after func main() or if true is a real compile error in Go, not a style nit. The formatter (gofmt) enforces brace placement along with everything else, which is part of why Go code across different codebases looks so similar.

Variables and zero values

var x int declares a variable with an explicit type. Left uninitialized, it gets that type's zero value, not garbage memory: 0 for numbers, "" for strings, false for bools, nil for pointers/slices/maps/interfaces/channels/functions. This is a real safety guarantee, not a convention, every variable is always in a valid, defined state.

go · live, editable, runnable

Inside a function, := declares and initializes in one step, inferring the type from the right-hand side. It's the idiomatic default for local variables. var is for when you want to be explicit about the type, when you're declaring without initializing, or at package level (:= only works inside functions).

go · live, editable, runnable

Constants and iota

const declares a compile-time constant. Constants can't be reassigned, and untyped numeric constants (like const Pi = 3.14159) can be used anywhere a compatible numeric type is expected without an explicit conversion, which typed variables can't do.

iota is Go's mechanism for auto-incrementing values inside a const block, most commonly used to build enumerations. It resets to 0 at the start of each const block and increments by one on each subsequent line.

go · live, editable, runnable

Try it yourself: add a String() method to Weekday (a switch over the value returning the day's name) and print Wednesday again. This is the standard pattern for readable enums in Go, since Go has no built-in enum type with named printing.