Skip to content

Commit cf9624b

Browse files
authored
Show if-case and for-case in the guide (#361)
This syntax was previously shown only in the reference, under Optional Patterns. Added a new section to the Control Flow chapter to discuss this, pattern-matching against tuples because that's the only suitable data type available at that point in the book. Added forward and backward cross-references to the section about enumerations that have associated values, because this syntax is the way you extract that associated value. Fixes: rdar://145579866
2 parents 378f76a + 2ef1828 commit cf9624b

File tree

2 files changed

+123
-8
lines changed

2 files changed

+123
-8
lines changed

TSPL.docc/LanguageGuide/ControlFlow.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,97 @@ and `distance` is an integer in both patterns ---
14401440
which means that the code in the body of the `case`
14411441
can always access a value for `distance`.
14421442

1443+
## Patterns
1444+
1445+
In the previous examples, each switch case includes a pattern
1446+
that indicates what values match that case.
1447+
You can also use a pattern as the condition for an `if` statement.
1448+
Here's what that looks like:
1449+
1450+
```swift
1451+
let somePoint = (12, 100)
1452+
if case (let x, 100) = somePoint {
1453+
print("Found a point on the y=100 line, at \(x)")
1454+
}
1455+
// Prints "Found a point on the y=100 line, at 12"
1456+
```
1457+
1458+
In this code,
1459+
the condition for the `if` statement starts with `case`,
1460+
indicating that the condition is a pattern instead of a Boolean value.
1461+
If the pattern matches,
1462+
then the condition for the `if` is considered to be true,
1463+
and so the code in the body of the `if` statement runs.
1464+
The patterns you can write after `if case`
1465+
are the same as the patterns you can write in a switch case.
1466+
1467+
In a `for`-`in` loop,
1468+
you can give names to parts of the value using a value binding pattern,
1469+
even without writing `case` in your code:
1470+
1471+
```swift
1472+
let points = [(10, 0), (30, -30), (-20, 0)]
1473+
1474+
for (x, y) in points {
1475+
if y == 0 {
1476+
print("Found a point on the x-axis at \(x)")
1477+
}
1478+
}
1479+
// Prints "Found a point on the x-axis at 10"
1480+
// Prints "Found a point on the x-axis at -20"
1481+
```
1482+
1483+
The `for`-`in` loop above iterates over an array of tuples,
1484+
binding the first and second elements of the tuples
1485+
to the `x` and `y` constants.
1486+
The statements inside the loop can use those constants,
1487+
such as the `if` statement that checks whether the point lies on the x-axis.
1488+
A more concise way to write this code
1489+
is to combine the value bindings and condition
1490+
using a `for`-`case`-`in` loop.
1491+
The code below has the same behavior as the `for`-`in` loop above:
1492+
1493+
```swift
1494+
for case (let x, 0) in points {
1495+
print("Found a point on the x-axis at \(x)")
1496+
}
1497+
// Prints "Found a point on the x-axis at 10"
1498+
// Prints "Found a point on the x-axis at -20"
1499+
```
1500+
1501+
In this code,
1502+
the condition is integrated into the `for`-`case`-`in` loop
1503+
as part of the pattern.
1504+
The statements in the `for`-`case`-`in` loop run only for points on the x-axis.
1505+
This code produces the same result as the `for`-`in` loop above,
1506+
but is a more compact way to iterate
1507+
over only certain elements in a collection.
1508+
1509+
A `for`-`case`-`in` loop can also include a `where` clause,
1510+
to check for an additional condition.
1511+
The statements inside the loop run
1512+
only when `where` clause matches the current element.
1513+
For example:
1514+
1515+
```swift
1516+
for case let (x, y) in points where x == y || x == -y {
1517+
print("Found (\(x), \(y)) along a line through the origin")
1518+
}
1519+
// Prints "Found (30, -30) along a line through the origin"
1520+
```
1521+
1522+
This code binds the first and second elements of the tuple
1523+
to `x` and `y` as constants,
1524+
and then checks their values in the `where` clause.
1525+
If the `where` clause is `true`,
1526+
then the code in the body of the `for` loop runs;
1527+
otherwise, iteration continues with the next element.
1528+
1529+
Because patterns can bind values,
1530+
`if`-`case` statements and `for`-`case`-`in` loops
1531+
are useful for working with enumerations that have associated values,
1532+
as described in <doc:Enumerations#Associated-Values>.
1533+
14431534
## Control Transfer Statements
14441535

14451536
*Control transfer statements* change the order in which your code is executed,

TSPL.docc/LanguageGuide/Enumerations.md

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,27 @@ case let .qrCode(productCode):
479479
```
480480
-->
481481

482+
When you're matching just one case of an enumeration ---
483+
for example,
484+
to extract its associated value ---
485+
you can use an `if`-`case` statement
486+
instead of writing a full switch statement.
487+
Here's what it looks like:
488+
489+
```swift
490+
if case .qrCode(let productCode) = productBarcode {
491+
print("QR code: \(productCode).")
492+
}
493+
```
494+
495+
Just like in the switch statement earlier,
496+
the `productBarcode` variable is matched against
497+
the pattern `.qrCode(let productCode)` here.
498+
And as in the switch case,
499+
writing `let` extracts the associated value as a constant.
500+
For more information about `if`-`case` statements,
501+
see <doc:ControlFlow#Patterns>.
502+
482503
## Raw Values
483504

484505
The barcode example in <doc:Enumerations#Associated-Values>
@@ -520,14 +541,17 @@ Raw values can be
520541
strings, characters, or any of the integer or floating-point number types.
521542
Each raw value must be unique within its enumeration declaration.
522543

523-
> Note: Raw values are *not* the same as associated values.
524-
> Raw values are set to prepopulated values
525-
> when you first define the enumeration in your code,
526-
> like the three ASCII codes above.
527-
> The raw value for a particular enumeration case is always the same.
528-
> Associated values are set when you create a new constant or variable
529-
> based on one of the enumeration's cases,
530-
> and can be different each time you do so.
544+
Although you can use both raw values and associated values
545+
to give an enumeration an additional value,
546+
it's important to understand the difference between them.
547+
You pick the raw value for an enumeration case
548+
when you define that enumeration case in your code,
549+
such as the three ASCII codes above.
550+
The raw value for a particular enumeration case is always the same.
551+
In contrast,
552+
you pick associated values when you create a new constant or variable
553+
using one of the enumeration's cases,
554+
and you can pick a different value each time you do so.
531555

532556
### Implicitly Assigned Raw Values
533557

0 commit comments

Comments
 (0)