03 - Decisions and Loops¶
What this session is¶
About an hour. You'll learn how to make your program decide between options (with if) and how to make it repeat something (with for). These two things are the building blocks of every program that does anything more than print a fixed message.
Decisions with if¶
The world's smallest decision:
package main
import "fmt"
func main() {
age := 18
if age >= 18 {
fmt.Println("adult")
} else {
fmt.Println("minor")
}
}
Run it. You'll see adult.
Now change age := 18 to age := 15 and run it again. You'll see minor.
What's happening:
if age >= 18 { ... }- run the code in the braces only ifage >= 18is true.else { ... }- if the condition was false, run this code instead.
The condition is whatever's between if and {. It must evaluate to a bool - true or false.
Comparison operators¶
The operators that produce true/false:
| Operator | Meaning |
|---|---|
== |
equal to |
!= |
not equal to |
< |
less than |
<= |
less than or equal to |
> |
greater than |
>= |
greater than or equal to |
A common mistake: writing = (one equals sign) when you mean == (two). = is assignment ("set this to that"); == is comparison ("does this equal that?"). Go will give a compile error if you mix them up; just notice it now.
Chaining decisions with else if¶
What if you have more than two cases?
score := 75
if score >= 90 {
fmt.Println("A")
} else if score >= 80 {
fmt.Println("B")
} else if score >= 70 {
fmt.Println("C")
} else {
fmt.Println("F")
}
Reads top to bottom. The first condition that's true wins; everything else is skipped. If none match, the else block runs.
Combining conditions: &&, ||, !¶
You can build bigger conditions out of smaller ones:
| Operator | Meaning | Example |
|---|---|---|
&& |
and (both true) | age >= 18 && hasLicense |
\|\| |
or (at least one true) | isWeekend \|\| isHoliday |
! |
not (flip true to false) | !isReady |
Example:
The condition is true only when both halves are true.
Repetition: for¶
This is the part that takes a few tries to internalize. Read carefully.
Print the numbers 1 through 5:
That for line is doing three things, separated by semicolons:
i := 1- create a variableistarting at 1. (This happens once, before anything else.)i <= 5- the condition that keeps the loop going. Checked before each round.i++- what to do after each round. (i++is shorthand fori = i + 1.)
The flow is:
- Set
i = 1. Check1 <= 5. True → run the body. Print1. Then doi++→i = 2. - Check
2 <= 5. True → print2. Theni = 3. - ... continues ...
- Check
5 <= 5. True → print5. Theni = 6. - Check
6 <= 5. False → stop.
Output:
Type this in. Run it. Change 1 to 10 and <= 5 to <= 20. Change i++ to i = i + 2 and see what happens. The way to internalize loops is to mess with them.
Two shorter forms¶
The "keep going while X" form, when you don't have a counter:
This prints 10, 9, 8, ..., 1. There's no "init" or "after each round" part - just the condition. The body has to do whatever changes the condition, otherwise the loop never stops.
The "forever" form, when you'll stop from inside:
Useful in programs that wait for events, listen on a socket, etc. We'll see real uses later.
Breaking out early: break and continue¶
break stops the loop entirely.
continue skips to the next round, without running the rest of the body this time.
for i := 1; i <= 10; i++ {
if i == 5 {
break // stop the whole loop when i is 5
}
if i%2 == 0 {
continue // skip the print for even numbers
}
fmt.Println(i)
}
Output: 1, 3. Why?
- i=1: not 5, not even → print
1. - i=2: not 5, even →
continue(skip print). - i=3: not 5, not even → print
3. - i=4: even → skip.
- i=5:
break→ stop entirely.
Putting it together¶
A small program that classifies the numbers 1 to 10:
package main
import "fmt"
func main() {
for i := 1; i <= 10; i++ {
if i%2 == 0 {
fmt.Println(i, "even")
} else {
fmt.Println(i, "odd")
}
}
}
Type and run. Read the output. Read the code. Look at each line and ask: which line produced this output?
Exercise¶
Type this in a new file called classify.go:
Write a program that, for each number from 1 to 20:
- If the number is divisible by 3, print
Fizzinstead of the number. - If the number is divisible by 5, print
Buzzinstead. - If divisible by both 3 and 5, print
FizzBuzz. - Otherwise print the number.
(This is the classic "FizzBuzz" problem. It's famous as a small interview question, and a very good exercise for cementing if/else if/else with a loop.)
Hint: check the "both 3 and 5" case first. Why? Think about what would happen if you checked "divisible by 3" first.
When you finish, the output should be:
Don't move on until your program prints exactly this.
What you might wonder¶
"What about while loops?"
Other languages have a separate while keyword. Go doesn't - for condition { } does the same thing. One loop keyword, fewer things to remember.
"What about do-while?"
Use:
"Why doesn't Go have i++ as an expression?"
In some languages j = i++ is legal and confusing. In Go, i++ is a statement on its own line - it doesn't return a value. This rules out a category of bugs that show up in C and C++.
"Why braces on if even for one line?"
In some languages you can write if (cond) doThing(); without braces. Go requires the braces always. This is opinionated but on purpose - a category of bugs (forgetting braces, then adding a second line that doesn't actually belong to the if) becomes impossible.
Done¶
You can now:
- Make a program take different actions based on conditions (if, else if, else).
- Combine conditions with &&, ||, !.
- Repeat actions with for, in three forms.
- Exit a loop early with break, skip an iteration with continue.
You now have the basic shapes that every program is built from. Combined with what you learned in Page 02, you can in principle write any program - just very, very long ones.
The next page is the abstraction that lets your programs stay short as they get bigger: functions.