8. Making decisions: `if` / `else`
if runs a block of code only when a condition is true. Go's version has one
small twist you'll come to love, and a couple of hard rules that keep the
code clean.
The basics
package main
import "fmt"
func main() {
temp := 30
if temp > 25 {
fmt.Println("It's warm.")
} else {
fmt.Println("It's cool.")
}
}
Two things set Go apart from most languages:
- No parentheses around the condition.
if temp > 25, notif (temp > 25). - Braces are mandatory, even for a single line. There's no brace-less
if. This alone prevents a famous category of bugs.
The condition must be a bool. You can't write if temp hoping non-zero
means true — Go requires an actual boolean expression.
else if chains
package main
import "fmt"
func main() {
score := 82
if score >= 90 {
fmt.Println("A")
} else if score >= 80 {
fmt.Println("B")
} else if score >= 70 {
fmt.Println("C")
} else {
fmt.Println("F")
}
}
Note the style Go enforces: } else if and } else { sit on the same line
as the closing brace. gofmt (Go's formatter) will insist on it.
The twist: an if with its own variable
An if can declare a variable that lives only inside the if/else. The
form is if <statement>; <condition>:
package main
import "fmt"
func main() {
if doubled := 21 * 2; doubled > 40 {
fmt.Println(doubled, "is big")
} else {
fmt.Println(doubled, "is small")
}
// doubled does not exist out here
}
Why is this so common in Go? Because functions often return a value and an error together, and you want to check the error right there without leaking the variable into the rest of your function. You'll see this exact shape everywhere once we reach errors:
package main
import (
"fmt"
"strconv"
)
func main() {
if n, err := strconv.Atoi("123"); err == nil {
fmt.Println("parsed:", n)
} else {
fmt.Println("not a number:", err)
}
}
Keeping n and err scoped to the if is idiomatic Go — it stops stale
variables from hanging around.
No ternary operator
Go deliberately has no ? : expression. If you want a value chosen by a
condition, you write a plain if. It's a few more lines, but every reader
knows exactly what it does:
package main
import "fmt"
func main() {
n := -8
label := "positive"
if n < 0 {
label = "negative"
}
fmt.Println(n, "is", label)
}
Your turn
Given year := 2024, print whether it's a leap year. The rule: a year is a
leap year if it's divisible by 4 and (not divisible by 100 or
divisible by 400). Use the modulo operator % (remainder). Print exactly:
2024 is a leap year
package main
import "fmt"
func main() {
year := 2024
// decide leap vs not, then print "<year> is a leap year"
// or "<year> is not a leap year"
}
package main
import "fmt"
func main() {
year := 2024
leap := year%4 == 0 && (year%100 != 0 || year%400 == 0)
if leap {
fmt.Printf("%d is a leap year\n", year)
} else {
fmt.Printf("%d is not a leap year\n", year)
}
}
Next: the loop — Go has exactly one, and it does everything.