Step 1 of 5 · Reading · ~3 min
Learn
Control Flow
if and switch
Swift's branching looks familiar if you have written C, Java or JavaScript — with one rule that trips up every newcomer and one construct that is far more capable than its namesake elsewhere.
A condition must be a Bool. Nothing else.
There is no truthiness in Swift. Not zero, not empty strings, not nil.
✗ Does not compile
let count = 5
if count { print("some") }
// error: cannot convert value of type 'Int' to expected condition type 'Bool'
✓ Compiles
let count = 5
if count > 0 { print("some") }
//> some
The same applies to strings (if !s.isEmpty) and optionals (if x != nil, or better, if let).
The braces are also mandatory — Swift has no brace-less single-statement if.
if / else if / else
let score = 87
if score >= 90 {
print("A")
} else if score >= 80 {
print("B")
} else {
print("F")
}
//> B
Order matters: the first matching branch wins and the rest are skipped. 87 satisfies
score >= 80, and because score >= 90 was tested first and failed, B is correct rather than
accidental.
For a two-way choice that produces a value, the ternary is shorter:
let n = 4
print(n % 2 == 0 ? "even" : "odd")
//> even
switch is a pattern matcher
Swift's switch is not C's. Three differences matter immediately:
| C / Java / JavaScript | Swift | |
|---|---|---|
| Falls through to the next case | yes, unless you break | no, never by default |
| Must cover every value | no | yes — or supply default |
| What a case can match | constants | ranges, tuples, types, conditions |
let n = 7
switch n {
case 0:
print("zero")
case 1...10:
print("low")
case let x where x < 0:
print("negative: \(x)")
default:
print("large")
}
//> low
Three things are happening there. case 1...10 matches a range. case let x where x < 0
binds the value to x and then applies an extra condition. default catches everything
else, and without it the compiler would reject the switch as non-exhaustive.
You can also match tuples and ignore parts with _:
let point = (2, 0)
switch point {
case (0, 0):
print("origin")
case (_, 0):
print("on the x axis")
case (0, _):
print("on the y axis")
case let (x, y):
print("at \(x), \(y)")
}
//> on the x axis
Cases are tested top to bottom and the first match wins — (2, 0) also matches the final
case let (x, y), but never reaches it. That ordering rule is the single most important thing to
remember about switch, and it is exactly what your exercise depends on.
Comma-separated cases, and opting in to fall-through
let day = "sat"
switch day {
case "sat", "sun":
print("weekend")
default:
print("weekday")
}
//> weekend
One case, two patterns. If you genuinely want C-style fall-through into the next case, the
keyword fallthrough opts in — it is rare, and the fact that you have to ask for it is the
point.
Your exercise
Read one integer and print FizzBuzz, Fizz, Buzz, or the number.
The mistake the grader catches is testing the wrong divisor first. Every multiple of 15 is
also a multiple of 3 and of 5, so if your first branch is n % 3 == 0 then input 15 prints
Fizz and the very first visible test fails:
| Input | % 3 checked first | % 15 checked first |
|---|---|---|
15 | Fizz ✗ | FizzBuzz ✓ |
9 | Fizz ✓ | Fizz ✓ |
10 | Buzz ✓ | Buzz ✓ |
Put the 15 case first, whether you use if / else if or a switch with a where clause. The
hidden test feeds 7 and wants the bare number, so your final branch must print n on its own
with no surrounding text.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…