Dev Skills

if, for, and switch

One loop keyword, no ternary, and cases that do not fall through.

Topic 8 of 98 · 5 min to read · 45 min to build
After this topic you can
  • Write the same loop as a three-part for, a condition-only for and a range loop.
  • Explain why a variable declared in if n := ...; cond cannot be used after the block.
  • Predict which switch case runs, knowing that cases do not fall through.

if — with a scoped variable

Go lets you declare a variable inside the if, scoped to the if and its else. Error handling uses this shape all the time: if err := save(u); err != nil { ... }.

flow.go
s := "golang"
if n := len(s); n > 3 {
fmt.Println("long:", n)
} else if n == 3 {
fmt.Println("exactly three")
} else {
fmt.Println("short")
}
// n does not exist out here — and that is the point
Note: There is no ternary operator in Go, and the Go FAQ explains why it was left out on purpose. Write the if. It is longer, and it stays readable when the condition grows.

for — the only loop

Go has one loop keyword. There is no while, no do..while, no foreach. for covers all of them by leaving parts out.

loops.go
for i := 0; i < 5; i++ { } // the classic three-part loop
i := 0
for i < 5 { i++ } // no init or post: this is a while loop
for { break } // no condition at all: infinite
for i, ch := range "héllo" { // range over a string gives byte index + rune
fmt.Println(i, string(ch))
}
nums := []int{10, 20, 30} // a slice: a list of values (Arrays and slices covers them)
for i, v := range nums { // index and value
fmt.Println(i, v)
}
for _, v := range nums { // "_" throws the index away
fmt.Println(v)
}
`range` also works on maps, which you will meet in **Maps**. Their order is random, on purpose.

switch — cleaner than it is elsewhere

Two things differ from C and Java. Cases do not fall through, so you never write break. And a switch with no expression is a tidy if/else chain, which is how most Go code writes three or more branches.

switch.go
switch day := 3; day {
case 1, 2, 3, 4, 5:
fmt.Println("weekday") // no break needed
case 6, 7:
fmt.Println("weekend")
default:
fmt.Println("invalid")
}
// switch with no expression — the idiomatic if/else chain
age := 30
switch {
case age < 13:
fmt.Println("child")
case age < 20:
fmt.Println("teenager")
default:
fmt.Println("adult")
}
If you do want fall-through, the keyword is `fallthrough`. You will rarely need it.

Try it yourself

press Run — this executes on the Go Playground
package main
import "fmt"
func main() {
for i := 1; i <= 15; i++ {
switch {
case i%15 == 0:
fmt.Println("FizzBuzz")
case i%3 == 0:
fmt.Println("Fizz")
case i%5 == 0:
fmt.Println("Buzz")
default:
fmt.Println(i)
}
}
if n := len("héllo"); n > 3 {
fmt.Println("byte length is", n) // 6, not 5
}
}
FizzBuzz with an expressionless switch, plus the scoped-variable `if`.
The short version
  • One loop keyword: for. Drop parts of it to get a while loop or an infinite one.
  • if n := len(s); n > 3 scopes the variable to the if and its else.
  • Cases do not fall through, so you never write break.
  • A switch with no expression is the idiomatic if/else chain.
Remember: There is no ternary operator. Write the if.
Build this before moving on
Write FizzBuzz twice, once with if/else and once with an expressionless switch, and keep the one you would rather read.
Coding challenge · checked by tests
Write Grade(score int) string. 90 to 100 is "A", 75 to 89 is "B", 50 to 74 is "C", 0 to 49 is "F", and anything below 0 or above 100 is "invalid". Example: Grade(82) → "B", Grade(101) → "invalid". Use a switch with no expression. The func line is written for you; the next lesson, Functions and errors, explains it.

Tab indents. Press Esc, then Tab, to leave the editor.

Then try these in your own editor
  1. 1Write the same loop four ways: three-clause, condition-only, infinite with break, and range.
  2. 2Use the scoped-variable if form, then try to use that variable after the block.
  3. 3Write a switch with fallthrough and see how it differs from C.
Check yourselfTake the Getting started test