1. What Go Is, and Installing the Toolchain
Go (often called Golang) is a statically typed, compiled language designed at Google for building simple, reliable, and efficient software — particularly network services. It compiles to a single self-contained binary with no runtime to install on the target machine, which is exactly why it became the language Docker, Kubernetes and most cloud-native tooling are written in.
# Download the installer from https://go.dev/dl/ for your OS, then confirm:
go version
# go version go1.2x.x darwin/amd64
# Everything Go needs lives under one environment variable
go env GOPATH
Unlike many languages, Go ships its formatter, test runner, dependency manager and
compiler as one go command. There's no separate build tool to choose
or configure — go build, go test, and go fmt
all just work out of the box, on every Go project you'll ever open.
2. Your First Program: go run vs. go build
Every executable Go program starts in package main, with a
main() function as its entry point:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
# Compile AND run in one step -- great for quick iteration
go run main.go
# Hello, Go!
# Compile to a standalone binary, then run it separately
go build main.go
./main # main.exe on Windows
# Hello, Go!
Go is deliberately strict here. Delete the fmt import above without using it and the program won't compile at all — this is one of the tools Go uses to keep codebases from accumulating dead code over time.
3. Variables & Constants
Go has two ways to declare a variable: the verbose var form, and the
short := form that infers the type from the right-hand side. You'll
use := constantly inside functions.
// Explicit type
var age int = 30
// Type inferred from the value
var name = "Ada"
// Short declaration -- only valid inside a function
score := 95
active := true
// Multiple variables at once
x, y := 10, 20
// Constants -- must be known at compile time, never reassigned
const Pi = 3.14159
const MaxRetries = 3
:= only works for a new variable inside a function body — at
package level, or to just reassign an existing variable, use = instead.
Mixing these up is one of the most common early Go compile errors.
4. Basic Types, Zero Values & Conversion
Go's built-in types cover the basics you'd expect: int,
float64, string, bool, plus sized variants
like int32 and int64 for when the size matters.
Every type has a zero value — the value a variable gets when it's
declared but not initialized, so nothing in Go is ever left as "uninitialized" or
undefined:
var i int // 0
var f float64 // 0.0
var s string // "" (empty string, not null)
var b bool // false
fmt.Println(i, f, s, b)
// 0 0 false
Go never converts types for you automatically, even between closely related numeric types — every conversion is explicit:
var whole int = 10
var precise float64 = float64(whole) / 3 // 3.3333...
// This does NOT compile -- int and float64 can't mix directly:
// var bad = whole / 3.0
var count int64 = 42
var smaller int32 = int32(count) // explicit, and can lose data on overflow
It eliminates an entire class of silent bugs where a language quietly converts between an int and a float and loses precision without telling you. In Go, if a conversion happens, you wrote it.
5. Packages & Managing Dependencies with go mod
Every Go file belongs to a package, declared at the top of the file. A module is a collection of packages versioned and distributed together — every real Go project starts by initializing one:
mkdir hello-go && cd hello-go
go mod init github.com/yourname/hello-go
# creates go.mod, recording the module path and Go version
# Add a third-party dependency
go get github.com/google/uuid
# updates go.mod AND go.sum (a lockfile of exact dependency hashes)
go mod tidy
# adds anything missing, removes anything unused -- run this often
go.mod is Go's equivalent of package.json;
go.sum is its lockfile. Commit both to version control — they're what
makes a Go build reproducible on any machine, including CI.
6. Hands-on Exercise
Build a tiny unit-conversion module
Practice the toolchain end to end: init a module, write code with explicit types, and run it.
Requirements:
- Run
go mod initto create a new module for a project calledunitconvert. - In
main.go, declare constants forCelsiusToFahrenheitOffset(32) and a variable for a temperature in Celsius using:=. - Write the Fahrenheit conversion using explicit
float64math — no implicit int/float mixing. - Print the zero value of an uninitialized
int,stringandboolwithfmt.Printlnso you can see all three at once. - Run it with
go run main.go, then compile it withgo buildand run the resulting binary directly.
If the compiler complains about a mismatched type in your Fahrenheit formula, you're almost certainly dividing or multiplying an int and a float64 directly — wrap the int side in float64(...) to convert it explicitly first.
7. Knowledge Check
Four quick questions. Expand each to check your answer.
Q1
What's the difference between go run and go build?
What's the difference between go run and go build?
go run compiles the program to a temporary location and executes it immediately in one step, without leaving a binary behind — convenient for quick iteration. go build compiles the program into a standalone executable file that you run separately and can distribute, without needing Go installed on the target machine.
Q2
Why does an unused import cause a compile error in Go, rather than just a warning?
Why does an unused import cause a compile error in Go, rather than just a warning?
Go's designers made this a hard error deliberately, as a forcing function against dead code and unused dependencies accumulating silently in a codebase over time. The same strictness applies to unused local variables — both must be either used or explicitly removed.
Q3
What is the zero value of a string in Go, and how is that different from null in other languages?
What is the zero value of a string in Go, and how is that different from null in other languages?
The zero value of a string is "" (an empty string), not null or nil. Go gives every type a sensible default zero value automatically, so a declared-but-unassigned variable is always in a valid, usable state rather than an undefined or null one.
Q4
Why doesn't var result = someInt / someFloat compile in Go?
Why doesn't var result = someInt / someFloat compile in Go?
Go never performs implicit type conversion, even between closely related numeric types like int and float64. Both operands of an arithmetic expression must be the same type, so one side needs an explicit conversion, e.g. float64(someInt) / someFloat, before the compiler will accept it.