Go/
Lesson

AI generates if/else blocks and operator expressions constantly. Most of the time they're correct, Go's operators are straightforward. But there are specific traps where AI-generated Go behaves differently than you'd expect from Python or JavaScript experience. This lesson focuses on those traps.

Arithmetic operators

The basics work as expected:

sum := 10 + 3      // 13
diff := 10 - 3     // 7
product := 10 * 3  // 30
quotient := 10 / 3 // 3 - integer division!
remainder := 10 % 3 // 1

That 10 / 3 = 3 is the first trap. Integer division in Go truncates, it doesn't round, and it doesn't return a float. This matches C behavior but surprises people from Python 3 (where / returns a float).

ExpressionGo resultPython 3 resultWhy different
10 / 333.333...Go: integer division truncates
10 % 311Same behavior
7 / 233.5Go: both operands are int → result is int
7.0 / 2.03.53.5Both are float → float division
-7 / 2-3-4Go truncates toward zero; Python floors

To get float division with integer variables:

a, b := 10, 3
result := float64(a) / float64(b)  // 3.333...
AI pitfall
AI often writes expressions like percentage := count / total * 100 where count and total are both int. If count is 3 and total is 10, you get 0 * 100 = 0 instead of 30. The fix is to convert to float64 before dividing: percentage := float64(count) / float64(total) * 100.
02

Comparison operators

x := 10
fmt.Println(x == 10)  // true
fmt.Println(x != 5)   // true
fmt.Println(x > 5)    // true
fmt.Println(x <= 10)  // true

Go only compares values of the same type. You can't compare an int to a float64 without converting:

var i int = 42
var f float64 = 42.0
// fmt.Println(i == f)           // COMPILE ERROR
fmt.Println(float64(i) == f)     // true - explicit conversion
AI pitfall
AI sometimes compares different numeric types directly, especially when one comes from a function return and the other is a literal. Go's compiler catches this, but if you're reviewing AI output mentally, watch for type mismatches in comparisons.

String comparison

Strings compare lexicographically (dictionary order) using ==, <, >:

fmt.Println("apple" < "banana")   // true
fmt.Println("Go" == "Go")         // true
fmt.Println("A" < "a")            // true - uppercase letters come first in UTF-8
Good to know
String comparison in Go is byte-by-byte using UTF-8 encoding. This means uppercase A (byte 65) is "less than" lowercase a (byte 97). For case-insensitive comparison, use strings.EqualFold("Go", "go").
03

Logical operators

x := 10
if x > 5 && x < 20 {    // AND - both must be true
    fmt.Println("in range")
}
if x < 5 || x > 8 {     // OR - at least one must be true
    fmt.Println("outside range")
}
if !false {              // NOT - inverts the boolean
    fmt.Println("true")
}

Go uses short-circuit evaluation: if the left side of && is false, the right side never runs. If the left side of || is true, the right side never runs. This matters when the right side has side effects.

// Safe: isValid() only called if user is not nil
if user != nil && isValid(user) {
    // ...
}
04

if/else, no parentheses, braces required

Go's if statements look cleaner than C-family languages because parentheses around the condition are not needed. But braces are always required, even for single-line bodies.

if temperature > 30 {
    fmt.Println("Hot")
} else if temperature > 20 {
    fmt.Println("Warm")
} else {
    fmt.Println("Cold")
}
Go ruleOther languagesWhy Go is different
No parentheses around conditionif (x > 0) in C/Java/JSCleaner syntax, less noise
Braces always requiredOptional for one-linersPrevents bugs from adding lines later
else must be on same line as }Flexible in most languagesGo parser requirement
Opening { on same lineSome allow next-lineGo parser requirement
AI pitfall
AI trained on JavaScript sometimes generates Go if blocks without braces for one-liners or puts else on a new line. Both are syntax errors:

> // WRONG, no braces
> if x > 0
>     fmt.Println("positive")
>
> // WRONG, else on new line
> if x > 0 {
>     fmt.Println("positive")
> }
> else {
>     fmt.Println("non-positive")
> }
>
> // CORRECT
> if x > 0 {
>     fmt.Println("positive")
> } else {
>     fmt.Println("non-positive")
> }
>
05

The init statement: Go's secret weapon

Go has a feature most languages don't: you can declare a variable inside an if condition. The variable is scoped to the if/else block.

if err := doSomething(); err != nil {
    fmt.Println("Error:", err)
    return
}
// err doesn't exist here - it's out of scope

The semicolon separates the init statement (err := doSomething()) from the condition (err != nil). This pattern is everywhere in Go because it keeps error-handling variables tightly scoped.

Compare with the non-init version:

err := doSomething()
if err != nil {
    fmt.Println("Error:", err)
    return
}
// err still exists here - "pollutes" the scope

Both work, but the init statement version is more idiomatic. You'll see it in every Go codebase. AI generates both styles; the init statement version is preferred when you only need the variable inside the if block.

Good to know
The init statement isn't limited to error handling. Any short statement works: if v := compute(); v > threshold { ... }. But the convention is to use it primarily for error checks.
06

Why there's no ternary operator

Coming from JavaScript (const x = cond ? a : b) or Python (x = a if cond else b), the lack of a ternary operator feels painful. It's deliberate.

Go's designers decided that ternary operators encourage writing dense, hard-to-read expressions. Instead, you write an if/else:

// What you can't write:
// status := age >= 18 ? "adult" : "minor"

// What you write instead:
var status string
if age >= 18 {
    status = "adult"
} else {
    status = "minor"
}
AI pitfall
AI sometimes tries to use a ternary operator in Go, especially models trained heavily on JavaScript or Python code. It will generate result := condition ? valueA : valueB. This is a syntax error. There's no workaround; you must use if/else. If you see a ternary in AI-generated Go, rewrite it immediately.
07

fmt.Printf format verbs

AI generates Printf calls frequently for formatted output. You need to read format verbs to verify the output matches what's intended:

name := "Alice"
age := 30
score := 95.5

fmt.Printf("Name: %s\n", name)         // %s - string
fmt.Printf("Age: %d\n", age)            // %d - decimal integer
fmt.Printf("Score: %.1f\n", score)       // %.1f - float, 1 decimal
fmt.Printf("Score: %v\n", score)         // %v - default format (any type)
fmt.Printf("Type: %T\n", score)          // %T - prints the type itself
fmt.Printf("Quoted: %q\n", name)         // %q - quoted string
VerbTypeExample output
%sstringAlice
%dinteger42
%ffloat3.141590
%.2ffloat (2 decimals)3.14
%vany (default format)Depends on type
%Tany (type name)int, string, etc.
%tbooltrue
%qquoted string"Alice"
%xhex2a
%bbinary101010
%%literal %%
AI pitfall
AI sometimes mismatches format verbs and argument types, using %s for an integer or %d for a string. Go doesn't catch this at compile time (it's a runtime format string), but go vet does. Always run go vet on AI-generated code to catch Printf mismatches.
08

Operator precedence

When AI generates complex expressions, knowing precedence helps you evaluate correctness without running the code:

Precedence (high → low)Operators
1 (highest)*, /, %
2+, -
3==, !=, <, >, <=, >=
4&&
5 (lowest)\|\|
// What does this evaluate to?
result := 2 + 3*4 > 10 && true
// Step 1: 3*4 = 12         (multiplication first)
// Step 2: 2 + 12 = 14      (addition)
// Step 3: 14 > 10 = true   (comparison)
// Step 4: true && true      (logical AND)
// result = true

When in doubt, use parentheses. Explicit grouping is always more readable than relying on precedence.

Good to know
Go has no power operator (**). For exponentiation, use math.Pow(base, exp). AI trained on Python sometimes generates x ** 2 in Go, that's a syntax error.
09

Combining it all: reading real Go patterns

Here's a typical AI-generated function. Read it and evaluate each line:

func categorize(scores []int) (int, int, int) {
    var high, medium, low int       // zero values: all 0

    for _, score := range scores {  // _ discards index
        if pct := float64(score) / 100.0; pct >= 0.8 {
            high++
        } else if pct >= 0.5 {
            medium++
        } else {
            low++
        }
    }

    return high, medium, low
}

This function uses: zero-value initialization, the blank identifier, float conversion to avoid integer division, an init statement in if, short-circuit else if chains, and multiple return values. Every pattern from this lesson and the previous ones, in nine lines.