Just another note about these Swift operators. One must remember that Swift has a very advanced and abstracted compiler, so keywords are just keywords, and their behavior depends on their usage.
Unlike C (and other syntactically related languages from C++ to JavaScript), where if
is simply used to test a Boolean value (or something that can be converted to one), in Swift, the concept of the if
statement is much more broad. I generally think of it gating access to a scope by using a variety of techniques, including Boolean tests.
You can think of if
, guard
, while
, and repeat
-while
as more general control flow statements, with much more advanced behavior. Certainly they can still test a Boolean value, but they can also test other conditions as well. In your scenario, the condition being tested is whether some variable matches a defined pattern (does age
match the pattern 20...30
).
You can also test whether a variable was successfully set to a non-nil
value (if let
). The result of the let
operation doesn't ever return a Boolean, but since it occurs within the if
statement, the Swift runtime knows that it's part of the control flow. Also note that this slightly changes the behavior of let
, insofar as any code inside the if
block now sees the new non-nil
value and is assured it's not nil
.
These behaviors can also be combined with commas, like this:
if !skipAgeTest, // `if` tests a Boolean
let age = Double(ageString), // `if` tests optional assignment
case 20...30 = age // `if` tests pattern matching
{
// `age` variable exists and is not `nil` and is between `20` and `30`, inclusive
}
so the concept of if let
or if case
being separate operators is... not exactly thinking about it in the right way.
And like I said, this syntax is also valid in other control flows:
while !skipAgeTest,
let age = Double(ageString),
case 20...30 = age {
// `age` is validated
// Probably also change `ageString` while we're in here
}
guard !skipAgeTest,
let age = Double(ageString),
case 20...30 = age
else {
// `age` is invalid, and not available in this block
}
// `age` is valid