Week 1: Go Fundamentals — Syntax, Types & the Toolchain

This course assumes basic programming knowledge but nothing about Go specifically. This week installs the toolchain, writes your first program, and builds a solid mental model of Go's type system — statically typed, but with enough inference that it rarely feels that way in practice.

Module 1 of 16 Week 1 of 16 ~2–3 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Install Go and explain the difference between go run and go build
  • Declare variables and constants, and explain what a zero value is
  • Start a module with go mod init and add a dependency

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.

terminal
# 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:

main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go!")
}
terminal
# 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!
An unused import or variable is a compile error, not a warning

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.

go
// 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:

go
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:

go
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
No implicit conversion is a feature, not friction

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:

terminal
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

Hands-on

Build a tiny unit-conversion module

Practice the toolchain end to end: init a module, write code with explicit types, and run it.

Requirements:

  1. Run go mod init to create a new module for a project called unitconvert.
  2. In main.go, declare constants for CelsiusToFahrenheitOffset (32) and a variable for a temperature in Celsius using :=.
  3. Write the Fahrenheit conversion using explicit float64 math — no implicit int/float mixing.
  4. Print the zero value of an uninitialized int, string and bool with fmt.Println so you can see all three at once.
  5. Run it with go run main.go, then compile it with go build and run the resulting binary directly.
Hint

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?

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?

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?

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?

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.