You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-17 14:47:35 +02:00
Comprehensive Rust v2 (#1073)
I've taken some work by @fw-immunant and others on the new organization of the course and condensed it into a form amenable to a text editor and some computational analysis. You can see the inputs in `course.py` but the interesting bits are the output: `outline.md` and `slides.md`. The idea is to break the course into more, smaller segments with exercises at the ends and breaks in between. So `outline.md` lists the segments, their duration, and sums those durations up per-day. It shows we're about an hour too long right now! There are more details of the segments in `slides.md`, or you can see mostly the same stuff in `course.py`. This now contains all of the content from the v1 course, ensuring both that we've covered everything and that we'll have somewhere to redirect every page. Fixes #1082. Fixes #1465. --------- Co-authored-by: Nicole LeGare <dlegare.1001@gmail.com> Co-authored-by: Martin Geisler <mgeisler@google.com>
This commit is contained in:
committed by
GitHub
parent
ea204774b6
commit
6d19292f16
10
src/tuples-and-arrays/Cargo.toml
Normal file
10
src/tuples-and-arrays/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "tuples-and-arrays"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "transpose"
|
||||
path = "exercise.rs"
|
||||
|
44
src/tuples-and-arrays/destructuring.md
Normal file
44
src/tuples-and-arrays/destructuring.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
minutes: 5
|
||||
---
|
||||
|
||||
# Destructuring
|
||||
|
||||
Destructuring is a way of extracting data from a data structure by writing a
|
||||
pattern that is matched up to the data structure, binding variables to
|
||||
subcomponents of the data structure.
|
||||
|
||||
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 array 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>
|
47
src/tuples-and-arrays/exercise.md
Normal file
47
src/tuples-and-arrays/exercise.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
minutes: 30
|
||||
---
|
||||
|
||||
# Exercise: Nested Arrays
|
||||
|
||||
Arrays can contain other arrays:
|
||||
|
||||
```rust
|
||||
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
|
||||
```
|
||||
|
||||
What is the type of this variable?
|
||||
|
||||
Use an array such as the above to write a function `transpose` which will
|
||||
transpose a matrix (turn rows into columns):
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
```bob
|
||||
⎛⎡1 2 3⎤⎞ ⎡1 4 7⎤
|
||||
"transpose"⎜⎢4 5 6⎥⎟ "=="⎢2 5 8⎥
|
||||
⎝⎣7 8 9⎦⎠ ⎣3 6 9⎦
|
||||
```
|
||||
|
||||
Hard-code both functions to operate on 3 × 3 matrices.
|
||||
|
||||
Copy the code below to <https://play.rust-lang.org/> and implement the
|
||||
functions:
|
||||
|
||||
```rust,should_panic
|
||||
// TODO: remove this when you're done with your implementation.
|
||||
#![allow(unused_variables, dead_code)]
|
||||
|
||||
{{#include exercise.rs:transpose}}
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
{{#include exercise.rs:main}}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
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>
|
60
src/tuples-and-arrays/exercise.rs
Normal file
60
src/tuples-and-arrays/exercise.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// ANCHOR: solution
|
||||
// ANCHOR: transpose
|
||||
fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
|
||||
// ANCHOR_END: transpose
|
||||
let mut result = [[0; 3]; 3];
|
||||
for i in 0..3 {
|
||||
for j in 0..3 {
|
||||
result[j][i] = matrix[i][j];
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// ANCHOR: tests
|
||||
#[test]
|
||||
fn test_transpose() {
|
||||
let matrix = [
|
||||
[101, 102, 103], //
|
||||
[201, 202, 203],
|
||||
[301, 302, 303],
|
||||
];
|
||||
let transposed = transpose(matrix);
|
||||
assert_eq!(
|
||||
transposed,
|
||||
[
|
||||
[101, 201, 301], //
|
||||
[102, 202, 302],
|
||||
[103, 203, 303],
|
||||
]
|
||||
);
|
||||
}
|
||||
// ANCHOR_END: tests
|
||||
|
||||
// ANCHOR: main
|
||||
fn main() {
|
||||
let matrix = [
|
||||
[101, 102, 103], // <-- the comment makes rustfmt add a newline
|
||||
[201, 202, 203],
|
||||
[301, 302, 303],
|
||||
];
|
||||
|
||||
println!("matrix: {:#?}", matrix);
|
||||
let transposed = transpose(matrix);
|
||||
println!("transposed: {:#?}", transposed);
|
||||
}
|
||||
// ANCHOR_END: main
|
28
src/tuples-and-arrays/iteration.md
Normal file
28
src/tuples-and-arrays/iteration.md
Normal file
@ -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>
|
50
src/tuples-and-arrays/match.md
Normal file
50
src/tuples-and-arrays/match.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
minutes: 10
|
||||
---
|
||||
|
||||
# Pattern Matching
|
||||
|
||||
The `match` keyword lets you match a value against one or more _patterns_. The
|
||||
comparisons are done from top to bottom and the first match wins.
|
||||
|
||||
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"),
|
||||
key if key.is_lowercase() => println!("Lowercase: {key}"),
|
||||
_ => println!("Something else"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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>
|
||||
|
||||
Key Points:
|
||||
* You might point out how some specific characters are being used when in a pattern
|
||||
* `|` as an `or`
|
||||
* `..` can expand as much as it needs to be
|
||||
* `1..=5` represents an inclusive range
|
||||
* `_` is a wild card
|
||||
|
||||
* 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.
|
||||
* The condition defined in the guard applies to every expression in a pattern with an `|`.
|
||||
</details>
|
5
src/tuples-and-arrays/solution.md
Normal file
5
src/tuples-and-arrays/solution.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Solution
|
||||
|
||||
```rust,editable
|
||||
{{#include exercise.rs:solution}}
|
||||
```
|
77
src/tuples-and-arrays/tuples-and-arrays.md
Normal file
77
src/tuples-and-arrays/tuples-and-arrays.md
Normal file
@ -0,0 +1,77 @@
|
||||
---
|
||||
minutes: 10
|
||||
---
|
||||
|
||||
# Tuples and Arrays
|
||||
|
||||
Tuples and arrays are the first "compound" types we have seen. All elements of
|
||||
an array have the same type, while tuples can accommodate different types.
|
||||
Both types have a size fixed at compile time.
|
||||
|
||||
| | Types | Literals |
|
||||
|--------|-------------------------------|-----------------------------------|
|
||||
| Arrays | `[T; N]` | `[20, 30, 40]`, `[0; 3]` |
|
||||
| Tuples | `()`, `(T,)`, `(T1, T2)`, ... | `()`, `('x',)`, `('x', 1.2)`, ... |
|
||||
|
||||
Array assignment and access:
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
```rust,editable
|
||||
fn main() {
|
||||
let mut a: [i8; 10] = [42; 10];
|
||||
a[5] = 0;
|
||||
println!("a: {a:?}");
|
||||
}
|
||||
```
|
||||
|
||||
Tuple assignment and access:
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
```rust,editable
|
||||
fn main() {
|
||||
let t: (i8, bool) = (7, true);
|
||||
println!("t.0: {}", t.0);
|
||||
println!("t.1: {}", t.1);
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
Key points:
|
||||
|
||||
Arrays:
|
||||
|
||||
* A value of the array type `[T; N]` holds `N` (a compile-time constant) elements of the same type `T`.
|
||||
Note that the length of the array is *part of its type*, which means that `[u8; 3]` and
|
||||
`[u8; 4]` are considered two different types. Slices, which have a size determined at runtime,
|
||||
are covered later.
|
||||
|
||||
* Try accessing an out-of-bounds array element. Array accesses are checked at
|
||||
runtime. Rust can usually optimize these checks away, and they can be avoided
|
||||
using unsafe Rust.
|
||||
|
||||
* We can use literals to assign values to arrays.
|
||||
|
||||
* The `println!` macro asks for the debug implementation with the `?` format
|
||||
parameter: `{}` gives the default output, `{:?}` gives the debug output. Types such as
|
||||
integers and strings implement the default output, but arrays only implement the debug output.
|
||||
This means that we must use debug output here.
|
||||
|
||||
* Adding `#`, eg `{a:#?}`, invokes a "pretty printing" format, which can be easier to read.
|
||||
|
||||
Tuples:
|
||||
|
||||
* Like arrays, tuples have a fixed length.
|
||||
|
||||
* Tuples group together values of different types into a compound type.
|
||||
|
||||
* Fields of a tuple can be accessed by the period and the index of the value, e.g. `t.0`, `t.1`.
|
||||
|
||||
* The empty tuple `()` is also known as the "unit type". It is both a type, and
|
||||
the only valid value of that type --- that is to say both the type and its value
|
||||
are expressed as `()`. It is used to indicate, for example, that a function or
|
||||
expression has no return value, as we'll see in a future slide.
|
||||
* You can think of it as `void` that can be familiar to you from other
|
||||
programming languages.
|
||||
|
||||
</details>
|
Reference in New Issue
Block a user