Section 04

Variables & Types

Python variables are names pointing to objects — no type declarations. Go variables have a fixed type at compile time. The type can be inferred from the right-hand side via :=, but once set, it never changes.

Declaration

Python
x = 42
name = "Alice"
ratio = 3.14
active = True
items = [1, "two", 3.0]  # mixed types
Go
x := 42                 // inferred int
name := "Alice"          // inferred string
ratio := 3.14            // inferred float64
active := true            // inferred bool
// items := []???        // no mixed-type slices

// Explicit form
var x int = 42
var name string = "Alice"

Zero Values

In Python, uninitialized variables don't exist — you get a NameError. In Go, every type has a zero value: the value a variable holds if you declare it without initialization.

Type Zero Value Python Equivalent
int, float640N/A (NameError)
string""N/A
boolfalseN/A
*T (pointer)nilNone
[]T (slice)nilNone (not [])
map[K]VnilNone (not {})
struct{}All fields zeroN/A

Type System

// Primitive types
var i int        // platform-dependent size (usually 64-bit)
var i32 int32    // explicit 32-bit
var f float64    // Python's float
var s string     // immutable UTF-8 byte sequence
var b bool
var by byte      // alias for uint8
var r rune       // alias for int32 (Unicode code point)

// Type conversion (no implicit casting, ever)
var x int = 42
var f float64 = float64(x)   // explicit
var s string = strconv.Itoa(x) // int → string (not just string(x))
string(42) Is Not "42"

string(42) produces "*" — the Unicode character at code point 42. To convert an integer to its string representation, use strconv.Itoa(42) or fmt.Sprintf("%d", 42). This trips up every Python developer exactly once.

Section 05

Functions

Go functions are statically typed, can return multiple values, and are first-class (can be assigned to variables, passed as arguments). There are no default arguments, no keyword arguments, no *args/**kwargs.

Python
def divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("division by zero")
    return a / b

# Default args, kwargs
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}"
Go
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

// No default args — use options pattern
func greet(name string) string {
    return "Hello, " + name
}

Multiple Return Values

Go's most distinctive feature. Functions routinely return (result, error). The caller must handle both. Python achieves this with exceptions; Go makes it explicit.

func parseConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("reading config: %w", err)
    }

    var cfg Config
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, fmt.Errorf("parsing config: %w", err)
    }

    return &cfg, nil
}

// Caller
cfg, err := parseConfig("config.json")
if err != nil {
    log.Fatal(err)
}

Closures & Function Values

// Functions are values — same as Python
func makeMultiplier(factor int) func(int) int {
    return func(x int) int {
        return x * factor  // captures factor
    }
}

double := makeMultiplier(2)
fmt.Println(double(5))  // 10

Variadic Functions

// Go's version of *args — typed, not arbitrary
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

sum(1, 2, 3)        // 6
sum(mySlice...)      // spread a slice
Section 06

Control Flow

Go's control flow is Python's with braces, no colons, mandatory braces, and no parentheses around conditions. The big addition: switch is far more powerful than Python's match and breaks by default (no fallthrough).

If / Else

Python
if x > 10:
    do_something()
elif x > 5:
    do_other()
else:
    fallback()
Go
if x > 10 {
    doSomething()
} else if x > 5 {
    doOther()
} else {
    fallback()
}

If with Init Statement

Go's killer feature for control flow — scope a variable to the if block:

// err only exists inside this if/else block
if err := doThing(); err != nil {
    return err
}
// err is not accessible here

For Loops

Go has one loop keyword: for. It replaces Python's for, while, and while True.

Python
# Iterate
for item in items:
    process(item)

# With index
for i, item in enumerate(items):
    process(i, item)

# While
while condition:
    do_work()

# Infinite
while True:
    tick()
Go
// Iterate
for _, item := range items {
    process(item)
}

// With index
for i, item := range items {
    process(i, item)
}

// While
for condition {
    doWork()
}

// Infinite
for {
    tick()
}

Switch

// No break needed — Go breaks automatically
switch status {
case "active":
    activate()
case "pending", "review":  // multiple values
    hold()
default:
    reject()
}

// Type switch — Go's pattern matching for types
switch v := val.(type) {
case string:
    fmt.Println("string:", v)
case int:
    fmt.Println("int:", v)
case nil:
    fmt.Println("nil")
}