Skip to content

Commit

Permalink
Edit the tuples-and-arrays segment
Browse files Browse the repository at this point in the history
  • Loading branch information
djmitche committed Sep 12, 2023
1 parent ee5e0b9 commit 5a54d73
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 203 deletions.
4 changes: 2 additions & 2 deletions book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@ line-numbers = true
'basic-syntax/functions-interlude.html' = '../control-flow-basics/functions.html'
'basic-syntax/type-inference.html' = '../type-inference-and-conversions/inference.html'
'basic-syntax/static-and-const.html' = '../type-inference-and-conversions/static-and-const.html'
'basic-syntax/compound-types.html' = '../tuples-and-arrays/tuples.html'
'basic-syntax/compound-types.html' = '../tuples-and-arrays.html'
'control-flow/match-expressions.html' = '../tuples-and-arrays/match.html'
'pattern-matching.html' = 'tuples-and-arrays/match.html'
'pattern-matching/match-guards.html' = '../tuples-and-arrays/match.html'
'pattern-matching/destructuring-arrays.html' = '../tuples-and-arrays/matching-arrays.html'
'pattern-matching/destructuring-arrays.html' = '../tuples-and-arrays/destructuring.html'
'exercises/day-1/for-loops.html' = '../../tuples-and-arrays/exercise.html'
'structs.html' = 'structs-and-enums/structs.html'
'structs/tuple-structs.html' = '../structs-and-enums/structs.html'
Expand Down
10 changes: 5 additions & 5 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@
# Day 1: Afternoon

- [Tuples and Arrays](tuples-and-arrays.md)
- [Tuples](tuples-and-arrays/tuples.md)
- [Match](tuples-and-arrays/match.md)
- [Arrays](tuples-and-arrays/arrays.md)
- [Matching Arrays](tuples-and-arrays/matching-arrays.md)
- [Exercise: Matrices as Nested Arrays](tuples-and-arrays/exercise.md)
- [Tuples and Arrays](tuples-and-arrays/tuples-and-arrays.md)
- [Array Iteration](tuples-and-arrays/iteration.md)
- [Pattern Matching](tuples-and-arrays/match.md)
- [Destructuring](tuples-and-arrays/destructuring.md)
- [Exercise: Nested Arrays](tuples-and-arrays/exercise.md)
- [Structs and Enums](structs-and-enums.md)
- [Overview of structs, naming conventions](structs-and-enums/overview.md)
- [Structs](structs-and-enums/structs.md)
Expand Down
10 changes: 5 additions & 5 deletions src/tuples-and-arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

In this segment:

* [Tuples](tuples-and-arrays/tuples.md)
* [Match](tuples-and-arrays/match.md)
* [Arrays](tuples-and-arrays/arrays.md)
* [Matching Arrays](tuples-and-arrays/matching-arrays.md)
* [Exercise: Matrices as Nested Arrays](tuples-and-arrays/exercise.md)
* [Tuples and Arrays](tuples-and-arrays/tuples-and-arrays.md)
* [Array Iteration](tuples-and-arrays/iteration.md)
* [Pattern Matching](tuples-and-arrays/match.md)
* [Destructuring](tuples-and-arrays/destructuring.md)
* [Exercise: Nested Arrays](tuples-and-arrays/exercise.md)
9 changes: 0 additions & 9 deletions src/tuples-and-arrays/arrays.md

This file was deleted.

40 changes: 40 additions & 0 deletions src/tuples-and-arrays/destructuring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
minutes: 5
---

# Destructuring

You can destructure tuples and arrays by matching on their elements:

## Tuples

```rust,editable
fn main() {
describe_point((1, 0));
}
fn describe_point(point: (i32, i32)) {
match point {
(0, _) => println!("on Y axis"),
(_, 0) => println!("on X axis"),
(x, _) if x < 0 => println!("left of Y axis"),
(_, y) if y < 0 => println!("below X axis"),
_ => println!("first quadrant"),
}
}
```

## Arrays

```rust,editable
{{#include ../../third_party/rust-by-example/destructuring-arrays.rs}}
```

<details>

* Create a new pattern using `_` to represent an element.
* Add more values to the array.
* Point out that how `..` will expand to account for different number of elements.
* Show matching against the tail with patterns `[.., b]` and `[a@..,b]`

</details>
70 changes: 9 additions & 61 deletions src/tuples-and-arrays/exercise.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,18 @@ minutes: 15
<!-- NOTES:
Simplify existing exercise, and drop bonus question
-->
# Exercise: Matrices as Nested Arrays
# Exercise: Nested Arrays

# Arrays and `for` Loops

We saw that an array can be declared like this:
Arrays can contain other arrays:

```rust
let array = [10, 20, 30];
```

You can print such an array by asking for its debug representation with `{:?}`:

```rust,editable
fn main() {
let array = [10, 20, 30];
println!("array: {array:?}");
}
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
```

Rust lets you iterate over things like arrays and ranges using the `for`
keyword:

```rust,editable
fn main() {
let array = [10, 20, 30];
print!("Iterating over array:");
for n in &array {
print!(" {n}");
}
println!();
print!("Iterating over range:");
for i in 0..3 {
print!(" {}", array[i]);
}
println!();
}
```
What is the type of this variable?

Use the above to write a function `pretty_print` which pretty-print a matrix and
a function `transpose` which will transpose a matrix (turn rows into columns):
Use an array such as the above to write a function `transpose` which will
transpose a matrix (turn rows into columns):

```bob
⎛⎡1 2 3⎤⎞ ⎡1 4 7⎤
Expand All @@ -66,36 +37,13 @@ functions:
unimplemented!()
}
{{#include exercise.rs:pretty_print}}
unimplemented!()
}
{{#include exercise.rs:main}}
```

## Bonus Question

Could you use `&[i32]` slices instead of hard-coded 3 × 3 matrices for your
argument and return types? Something like `&[&[i32]]` for a two-dimensional
slice-of-slices. Why or why not?


See the [`ndarray` crate](https://docs.rs/ndarray/) for a production quality
implementation.

<details>

The solution and the answer to the bonus section are available in the
[Solution](solutions-morning.md#arrays-and-for-loops) section.

The use of the reference `&array` within `for n in &array` is a subtle
preview of issues of ownership that will come later in the afternoon.

Without the `&`...
* The loop would have been one that consumes the array. This is a
change [introduced in the 2021
Edition](https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html).
* An implicit array copy would have occurred. Since `i32` is a copy type, then
`[i32; 3]` is also a copy type.
The `transpose` function takes its argument by value, but we haven't covered
ownership yet. Try printing a matrix after it has been transposed, to show the
"value has been moved" error, as a preview of ownership and move semantics.

</details>
18 changes: 4 additions & 14 deletions src/tuples-and-arrays/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,7 @@ fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
result[j][i] = matrix[i][j];
}
}
return result;
}

// ANCHOR: pretty_print
fn pretty_print(matrix: &[[i32; 3]; 3]) {
// ANCHOR_END: pretty_print
for row in matrix {
println!("{row:?}");
}
result
}

// ANCHOR: tests
Expand Down Expand Up @@ -60,10 +52,8 @@ fn main() {
[301, 302, 303],
];

println!("matrix:");
pretty_print(&matrix);

println!("matrix: {:#?}", matrix);
let transposed = transpose(matrix);
println!("transposed:");
pretty_print(&transposed);
println!("transposed: {:#?}", transposed);
}
// ANCHOR_END: main
28 changes: 28 additions & 0 deletions src/tuples-and-arrays/iteration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
minutes: 3
---

# Array Iteration

The `for` statement supports iterating over arrays (but not tuples).

```rust,editable
fn main() {
let primes = [2, 3, 5, 7, 11, 13, 17, 19];
for prime in primes {
for i in 2..prime {
assert_ne!(prime % i, 0);
}
}
}
```

<details>

This functionality uses the `IntoIterator` trait, but we haven't covered that yet.

The `assert_ne!` macro is new here. There are also `assert_eq!` and `assert!`
macros. These are always checked while, debug-only variants like
`debug_assert!` compile to nothing in release builds.

</details>
74 changes: 16 additions & 58 deletions src/tuples-and-arrays/match.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,6 @@ minutes: 10
<!-- NOTES:
Match as statement / expression, matching on ranges, guard expressions
-->
# Match

# `match` expressions

The [`match` keyword](https://doc.rust-lang.org/reference/expressions/match-expr.html)
is used to match a value against one or more patterns. In that sense, it works
like a series of `if let` expressions:

```rust,editable
fn main() {
match std::env::args().next().as_deref() {
Some("cat") => println!("Will do cat things"),
Some("ls") => println!("Will ls some files"),
Some("mv") => println!("Let's move some files"),
Some("rm") => println!("Uh, dangerous!"),
None => println!("Hmm, no program name?"),
_ => println!("Unknown program name!"),
}
}
```

Like `if let`, each match arm must have the same type. The type is the last
expression of the block, if any. In the example above, the type is `()`.

See [pattern matching](../pattern-matching.md) for more details on patterns in
Rust.

<details>

* Save the match expression to a variable and print it out.
* Remove `.as_deref()` and explain the error.
* `std::env::args().next()` returns an `Option<String>`, but we cannot match against `String`.
* `as_deref()` transforms an `Option<T>` to `Option<&T::Target>`. In our case, this turns `Option<String>` into `Option<&str>`.
* We can now use pattern matching to match against the `&str` inside `Option`.
</details>
# Pattern Matching

The `match` keyword let you match a value against one or more _patterns_. The
Expand All @@ -50,17 +15,27 @@ The patterns can be simple values, similarly to `switch` in C and C++:
```rust,editable
fn main() {
let input = 'x';
match input {
'q' => println!("Quitting"),
'a' | 's' | 'w' | 'd' => println!("Moving around"),
'0'..='9' => println!("Number input"),
_ => println!("Something else"),
'q' => println!("Quitting"),
'a' | 's' | 'w' | 'd' => println!("Moving around"),
'0'..='9' => println!("Number input"),
key if key.is_lowercase() => println!("Lowercase: {key}"),
_ => println!("Something else"),
}
}
```

The `_` pattern is a wildcard pattern which matches any value.
The `_` pattern is a wildcard pattern which matches any value. The expressions
_must_ be irrefutable, meaning that it covers every possibility, so `_` is
often used as the final catch-all case.

Match can be used as an expression. Just like like `if`, each match arm must have the same type. The type is the last
expression of the block, if any. In the example above, the type is `()`.

A variable in the pattern (`key` in this example) will create a binding that
can be used within the match arm.

A match guard causes the arm to match only if the condition is true.

<details>

Expand All @@ -70,26 +45,9 @@ Key Points:
* `..` can expand as much as it needs to be
* `1..=5` represents an inclusive range
* `_` is a wild card
* It can be useful to show how binding works, by for instance replacing a wildcard character with a variable, or removing the quotes around `q`.
* You can demonstrate matching on a reference.
* This might be a good time to bring up the concept of irrefutable patterns, as the term can show up in error messages.

</details>
# Match Guards

When matching, you can add a _guard_ to a pattern. This is an arbitrary Boolean
expression which will be executed if the pattern matches:

```rust,editable
{{#include ../../third_party/rust-by-example/match-guards.rs}}
```

<details>

Key Points:
* Match guards as a separate syntax feature are important and necessary when we wish to concisely express more complex ideas than patterns alone would allow.
* They are not the same as separate `if` expression inside of the match arm. An `if` expression inside of the branch block (after `=>`) happens after the match arm is selected. Failing the `if` condition inside of that block won't result in other arms
of the original `match` expression being considered.
* You can use the variables defined in the pattern in your if expression.
* The condition defined in the guard applies to every expression in a pattern with an `|`.
</details>
46 changes: 0 additions & 46 deletions src/tuples-and-arrays/matching-arrays.md

This file was deleted.

Loading

0 comments on commit 5a54d73

Please sign in to comment.