Knaph

If

Go deliberately has fewer control-flow keywords than most languages. There's no while, no do-while, no ternary operator. Once you know why, it stops feeling like a missing feature and starts feeling like one less thing to decide between.

if

age := 20
 
if age >= 18 {
	fmt.Println("adult")
} else if age >= 13 {
	fmt.Println("teen")
} else {
	fmt.Println("child")
}

Two things jump out coming from most other languages: no parentheses around the condition, and the braces are mandatory — you can't write a one-line if without them. Both are enforced by the compiler, not just a style guide, which means every Go codebase you read looks like this one.

if also accepts an initializer statement — a short statement that runs right before the condition is checked, scoped to just the if/else chain. It looks unfamiliar at first, so let's build up to it in pieces, using only what you already know: := and comparisons.

Here's the same code written two ways. First, as two separate lines:

x := 10
if x > 5 {
	fmt.Println("big:", x)
} else {
	fmt.Println("small:", x)
}

Now with the initializer folded into the if, using a semicolon to separate the setup statement from the condition:

if x := 10; x > 5 {
	fmt.Println("big:", x)
} else {
	fmt.Println("small:", x)
}

Read it as two statements glued together — x := 10 runs first, then x > 5 is checked as the condition, exactly like the two-line version above. The semicolon is the seam: everything before it is the initializer, everything after it is the condition.

Why fold it in at all? Scope. A variable declared in the initializer only exists inside the if/else if/else chain it belongs to — not in the rest of the function:

if x := 10; x > 5 {
	fmt.Println("big:", x)
}
fmt.Println(x) // compile error: undefined: x

With the two-line version, x would still be sitting in the function's scope after the if block ends — available to be misused, or to collide with another variable named x later on.

This becomes genuinely useful once a statement can produce more than one value — which is exactly what you'll see in the upcoming Functions and Errors lessons later in this module, in patterns like:

if err := doSomething(); err != nil {
	return err
}

Here err only needs to exist long enough to be checked, then it's gone — the next line down can declare its own err := ... with no conflict. You'll see this constantly once functions and errors are in play; for now, the thing to hold onto is just this: if can run a short setup statement right before its condition, and whatever that statement declares only lives inside that if/else chain.

No ternary operator

Python has x if cond else y; Go has nothing shorter than a full if/else. This is intentional — the language designers left it out on purpose to avoid the nested-ternary readability problem, and the idiomatic replacement is just to write the if:

status := "child"
if age >= 18 {
	status = "adult"
}

It's a few more lines than a ternary. Once you've read enough Go, you'll find you stop missing it.

Sign in to track your progress through this course.

Ask an AI

Open a ready-made prompt in ChatGPT or Claude — just press Enter.

SummarizeChatGPTClaude
Ask me questionsChatGPTClaude
Let's learn togetherChatGPTClaude