You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-07-09 15:55:36 +02:00
Format all Markdown files with dprint
(#1157)
This is the result of running `dprint fmt` after removing `src/` from the list of excluded directories. This also reformats the Rust code: we might want to tweak this a bit in the future since some of the changes removes the hand-formatting. Of course, this formatting can be seen as a mis-feature, so maybe this is good overall. Thanks to mdbook-i18n-helpers 0.2, the POT file is nearly unchanged after this, meaning that all existing translations remain valid! A few messages were changed because of stray whitespace characters: msgid "" "Slices always borrow from another object. In this example, `a` has to remain " -"'alive' (in scope) for at least as long as our slice. " +"'alive' (in scope) for at least as long as our slice." msgstr "" The formatting is enforced in CI and we will have to see how annoying this is in practice for the many contributors. If it becomes annoying, we should look into fixing dprint/check#11 so that `dprint` can annotate the lines that need fixing directly, then I think we can consider more strict formatting checks. I added more customization to `rustfmt.toml`. This is to better emulate the dense style used in the course: - `max_width = 85` allows lines to take up the full width available in our code blocks (when taking margins and the line numbers into account). - `wrap_comments = true` ensures that we don't show very long comments in the code examples. I edited some comments to shorten them and avoid unnecessary line breaks — please trim other unnecessarily long comments when you see them! Remember we're writing code for slides 😄 - `use_small_heuristics = "Max"` allows for things like struct literals and if-statements to take up the full line width configured above. The formatting settings apply to all our Rust code right now — I think we could improve this with https://github.com/dprint/dprint/issues/711 which lets us add per-directory `dprint` configuration files. However, the `inherit: true` setting is not yet implemented (as far as I can tell), so a nested configuration file will have to copy most or all of the top-level file.
This commit is contained in:
dprint.json
mdbook-course/src
mdbook-exerciser/src
po
rustfmt.tomlsrc
SUMMARY.mdandroid.mdalloc.mdandroid.md
android
aidl.mdsetup.md
async.mdaidl
build-rules.mdbuild-rules
interoperability.mdinteroperability
cpp
android-build-cpp.mdandroid-cpp-genrules.mdbridge.mdcpp-bridge.mdcpp-exception.mdrust-bridge.mdrust-result.mdshared-enums.mdshared-types.mdtype-mapping.md
java.mdwith-c.mdwith-c
async
bare-metal.mdbare-metal
alloc-example
src
android
aps.mdaps
better-uart.md
microcontrollers.mdbetter-uart
entry-point.mdexamples
exceptions.mdinline-assembly.mdlogging.mdlogging
mmio.mdother-projects.mduart.mduart
microcontrollers
board-support.mddebugging.mdembedded-hal.mdhals.mdmmio.mdother-projects.mdpacs.mdprobe-rs.mdtype-state.md
minimal.mdno_std.mduseful-crates.mdexamples
src
useful-crates
borrowing
cargo.mdcargo
chromium.mdchromium
adding-third-party-crates.md
concurrency.mdadding-third-party-crates
checking-in.mdconfiguring-cargo-toml.mdconfiguring-gnrt-config-toml.mddepending-on-a-crate.mddownloading-crates.mdgenerating-gn-build-rules.mdkeeping-up-to-date.mdresolving-problems.md
build-rules.mdresolving-problems
reviews-and-audits.mdbuild-rules
cargo.mdinteroperability-with-cpp.mdinteroperability-with-cpp
error-handling-png.mderror-handling-qr.mderror-handling.mdexample-bindings.mdlimitations-of-cxx.mdusing-cxx-in-chromium.md
policy.mdsetup.mdtesting.mdtesting
concurrency
control-flow-basics
credits.mderror-handling
exercises
android
bare-metal
chromium
bringing-it-together.mdbuild-rules.mdinteroperability-with-cpp.mdsolutions.mdtesting.mdthird-party.md
concurrency
generics
glossary.mdhello-world
index.mditerators
memory-management
methods-and-traits
modules
other-resources.mdpattern-matching
references
running-the-course.mdrunning-the-course
slices-and-lifetimes
exercise.mdexercise.rslifetime-annotations.mdlifetime-elision.mdslices.mdsolution.mdstr.mdstruct-lifetimes.md
smart-pointers
std-traits
std-types
testing
thanks.mdtuples-and-arrays
types-and-values
unsafe-rust
dereferencing.mdexercise.mdexercise.rsmutable-static.mdunions.mdunsafe-functions.mdunsafe-traits.mdunsafe.md
user-defined-types
welcome-day-1.mdwelcome-day-2.mdwelcome-day-3.mdwelcome-day-4.md@ -6,9 +6,13 @@ minutes: 5
|
||||
|
||||
Rust comes with extensive documentation. For example:
|
||||
|
||||
* All of the details about [loops](https://doc.rust-lang.org/stable/reference/expressions/loop-expr.html).
|
||||
* Primitive types like [`u8`](https://doc.rust-lang.org/stable/std/primitive.u8.html).
|
||||
* Standard library types like [`Option`](https://doc.rust-lang.org/stable/std/option/enum.Option.html) or [`BinaryHeap`](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html).
|
||||
- All of the details about
|
||||
[loops](https://doc.rust-lang.org/stable/reference/expressions/loop-expr.html).
|
||||
- Primitive types like
|
||||
[`u8`](https://doc.rust-lang.org/stable/std/primitive.u8.html).
|
||||
- Standard library types like
|
||||
[`Option`](https://doc.rust-lang.org/stable/std/option/enum.Option.html) or
|
||||
[`BinaryHeap`](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html).
|
||||
|
||||
In fact, you can document your own code:
|
||||
|
||||
@ -29,8 +33,8 @@ automatically documented at [`docs.rs`](https://docs.rs) using the
|
||||
[rustdoc](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html) tool. It is
|
||||
idiomatic to document all public items in an API using this pattern.
|
||||
|
||||
To document an item from inside the item (such as inside a module), use `//!`
|
||||
or `/*! .. */`, called "inner doc comments":
|
||||
To document an item from inside the item (such as inside a module), use `//!` or
|
||||
`/*! .. */`, called "inner doc comments":
|
||||
|
||||
```rust,editable
|
||||
//! This module contains functionality relating to divisibility of integers.
|
||||
@ -38,7 +42,7 @@ or `/*! .. */`, called "inner doc comments":
|
||||
|
||||
<details>
|
||||
|
||||
* Show students the generated docs for the `rand` crate at
|
||||
- Show students the generated docs for the `rand` crate at
|
||||
<https://docs.rs/rand>.
|
||||
|
||||
</details>
|
||||
|
@ -25,9 +25,7 @@ struct Counter<T: Eq + Hash> {
|
||||
impl<T: Eq + Hash> Counter<T> {
|
||||
/// Create a new Counter.
|
||||
fn new() -> Self {
|
||||
Counter {
|
||||
values: HashMap::new(),
|
||||
}
|
||||
Counter { values: HashMap::new() }
|
||||
}
|
||||
|
||||
/// Count an occurrence of the given value.
|
||||
|
@ -16,14 +16,16 @@ fn main() {
|
||||
page_counts.insert("Pride and Prejudice".to_string(), 303);
|
||||
|
||||
if !page_counts.contains_key("Les Misérables") {
|
||||
println!("We know about {} books, but not Les Misérables.",
|
||||
page_counts.len());
|
||||
println!(
|
||||
"We know about {} books, but not Les Misérables.",
|
||||
page_counts.len()
|
||||
);
|
||||
}
|
||||
|
||||
for book in ["Pride and Prejudice", "Alice's Adventure in Wonderland"] {
|
||||
match page_counts.get(book) {
|
||||
Some(count) => println!("{book}: {count} pages"),
|
||||
None => println!("{book} is unknown.")
|
||||
None => println!("{book} is unknown."),
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,33 +41,42 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
* `HashMap` is not defined in the prelude and needs to be brought into scope.
|
||||
* Try the following lines of code. The first line will see if a book is in the hashmap and if not return an alternative value. The second line will insert the alternative value in the hashmap if the book is not found.
|
||||
- `HashMap` is not defined in the prelude and needs to be brought into scope.
|
||||
- Try the following lines of code. The first line will see if a book is in the
|
||||
hashmap and if not return an alternative value. The second line will insert
|
||||
the alternative value in the hashmap if the book is not found.
|
||||
|
||||
```rust,ignore
|
||||
let pc1 = page_counts
|
||||
.get("Harry Potter and the Sorcerer's Stone")
|
||||
.unwrap_or(&336);
|
||||
let pc2 = page_counts
|
||||
.entry("The Hunger Games".to_string())
|
||||
.or_insert(374);
|
||||
```
|
||||
* Unlike `vec!`, there is unfortunately no standard `hashmap!` macro.
|
||||
* Although, since Rust 1.56, HashMap implements [`From<[(K, V); N]>`][1], which allows us to easily initialize a hash map from a literal array:
|
||||
```rust,ignore
|
||||
let pc1 = page_counts
|
||||
.get("Harry Potter and the Sorcerer's Stone")
|
||||
.unwrap_or(&336);
|
||||
let pc2 = page_counts
|
||||
.entry("The Hunger Games".to_string())
|
||||
.or_insert(374);
|
||||
```
|
||||
- Unlike `vec!`, there is unfortunately no standard `hashmap!` macro.
|
||||
- Although, since Rust 1.56, HashMap implements [`From<[(K, V); N]>`][1],
|
||||
which allows us to easily initialize a hash map from a literal array:
|
||||
|
||||
```rust,ignore
|
||||
let page_counts = HashMap::from([
|
||||
("Harry Potter and the Sorcerer's Stone".to_string(), 336),
|
||||
("The Hunger Games".to_string(), 374),
|
||||
]);
|
||||
```
|
||||
```rust,ignore
|
||||
let page_counts = HashMap::from([
|
||||
("Harry Potter and the Sorcerer's Stone".to_string(), 336),
|
||||
("The Hunger Games".to_string(), 374),
|
||||
]);
|
||||
```
|
||||
|
||||
* Alternatively HashMap can be built from any `Iterator` which yields key-value tuples.
|
||||
* We are showing `HashMap<String, i32>`, and avoid using `&str` as key to make examples easier. Using references in collections can, of course, be done,
|
||||
but it can lead into complications with the borrow checker.
|
||||
* Try removing `to_string()` from the example above and see if it still compiles. Where do you think we might run into issues?
|
||||
- Alternatively HashMap can be built from any `Iterator` which yields key-value
|
||||
tuples.
|
||||
- We are showing `HashMap<String, i32>`, and avoid using `&str` as key to make
|
||||
examples easier. Using references in collections can, of course, be done, but
|
||||
it can lead into complications with the borrow checker.
|
||||
- Try removing `to_string()` from the example above and see if it still
|
||||
compiles. Where do you think we might run into issues?
|
||||
|
||||
* This type has several "method-specific" return types, such as `std::collections::hash_map::Keys`. These types often appear in searches of the Rust docs. Show students the docs for this type, and the helpful link back to the `keys` method.
|
||||
- This type has several "method-specific" return types, such as
|
||||
`std::collections::hash_map::Keys`. These types often appear in searches of
|
||||
the Rust docs. Show students the docs for this type, and the helpful link back
|
||||
to the `keys` method.
|
||||
|
||||
[1]: https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#impl-From%3C%5B(K,+V);+N%5D%3E-for-HashMap%3CK,+V,+RandomState%3E
|
||||
|
||||
|
@ -4,8 +4,8 @@ minutes: 10
|
||||
|
||||
# Option
|
||||
|
||||
We have already seen some use of `Option<T>`. It stores either a
|
||||
value of type `T` or nothing. For example,
|
||||
We have already seen some use of `Option<T>`. It stores either a value of type
|
||||
`T` or nothing. For example,
|
||||
[`String::find`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.find)
|
||||
returns an `Option<usize>`.
|
||||
|
||||
@ -23,10 +23,14 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
* `Option` is widely used, not just in the standard library.
|
||||
* `unwrap` will return the value in an `Option`, or panic. `expect` is similar but takes an error message.
|
||||
* You can panic on None, but you can't "accidentally" forget to check for None.
|
||||
* It's common to `unwrap`/`expect` all over the place when hacking something together, but production code typically handles `None` in a nicer fashion.
|
||||
* The niche optimization means that `Option<T>` often has the same size in memory as `T`.
|
||||
- `Option` is widely used, not just in the standard library.
|
||||
- `unwrap` will return the value in an `Option`, or panic. `expect` is similar
|
||||
but takes an error message.
|
||||
- You can panic on None, but you can't "accidentally" forget to check for
|
||||
None.
|
||||
- It's common to `unwrap`/`expect` all over the place when hacking something
|
||||
together, but production code typically handles `None` in a nicer fashion.
|
||||
- The niche optimization means that `Option<T>` often has the same size in
|
||||
memory as `T`.
|
||||
|
||||
</details>
|
||||
|
@ -5,9 +5,9 @@ minutes: 10
|
||||
# Result
|
||||
|
||||
`Result` is similar to `Option`, but indicates the success or failure of an
|
||||
operation, each with a different type. This is similar to the `Res` defined
|
||||
in the expression exercise, but generic: `Result<T, E>` where `T` is used in
|
||||
the `Ok` variant and `E` appears in the `Err` variant.
|
||||
operation, each with a different type. This is similar to the `Res` defined in
|
||||
the expression exercise, but generic: `Result<T, E>` where `T` is used in the
|
||||
`Ok` variant and `E` appears in the `Err` variant.
|
||||
|
||||
```rust,editable
|
||||
use std::fs::File;
|
||||
@ -23,7 +23,7 @@ fn main() {
|
||||
} else {
|
||||
println!("Could not read file content");
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
println!("The diary could not be opened: {err}");
|
||||
}
|
||||
@ -33,11 +33,14 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
* As with `Option`, the successful value sits inside of `Result`, forcing the developer to
|
||||
explicitly extract it. This encourages error checking. In the case where an error should never happen,
|
||||
`unwrap()` or `expect()` can be called, and this is a signal of the developer intent too.
|
||||
* `Result` documentation is a recommended read. Not during the course, but it is worth mentioning.
|
||||
It contains a lot of convenience methods and functions that help functional-style programming.
|
||||
* `Result` is the standard type to implement error handling as we will see on Day 3.
|
||||
- As with `Option`, the successful value sits inside of `Result`, forcing the
|
||||
developer to explicitly extract it. This encourages error checking. In the
|
||||
case where an error should never happen, `unwrap()` or `expect()` can be
|
||||
called, and this is a signal of the developer intent too.
|
||||
- `Result` documentation is a recommended read. Not during the course, but it is
|
||||
worth mentioning. It contains a lot of convenience methods and functions that
|
||||
help functional-style programming.
|
||||
- `Result` is the standard type to implement error handling as we will see on
|
||||
Day 3.
|
||||
|
||||
</details>
|
||||
|
@ -8,8 +8,11 @@ Rust comes with a standard library which helps establish a set of common types
|
||||
used by Rust libraries and programs. This way, two libraries can work together
|
||||
smoothly because they both use the same `String` type.
|
||||
|
||||
In fact, Rust contains several layers of the Standard Library: `core`, `alloc` and `std`.
|
||||
* `core` includes the most basic types and functions that don't depend on `libc`, allocator or
|
||||
even the presence of an operating system.
|
||||
* `alloc` includes types which require a global heap allocator, such as `Vec`, `Box` and `Arc`.
|
||||
* Embedded Rust applications often only use `core`, and sometimes `alloc`.
|
||||
In fact, Rust contains several layers of the Standard Library: `core`, `alloc`
|
||||
and `std`.
|
||||
|
||||
- `core` includes the most basic types and functions that don't depend on
|
||||
`libc`, allocator or even the presence of an operating system.
|
||||
- `alloc` includes types which require a global heap allocator, such as `Vec`,
|
||||
`Box` and `Arc`.
|
||||
- Embedded Rust applications often only use `core`, and sometimes `alloc`.
|
||||
|
@ -18,30 +18,41 @@ fn main() {
|
||||
println!("s2: len = {}, capacity = {}", s2.len(), s2.capacity());
|
||||
|
||||
let s3 = String::from("🇨🇭");
|
||||
println!("s3: len = {}, number of chars = {}", s3.len(),
|
||||
s3.chars().count());
|
||||
println!("s3: len = {}, number of chars = {}", s3.len(), s3.chars().count());
|
||||
}
|
||||
```
|
||||
|
||||
`String` implements [`Deref<Target = str>`][2], which means that you can call all
|
||||
`str` methods on a `String`.
|
||||
`String` implements [`Deref<Target = str>`][2], which means that you can call
|
||||
all `str` methods on a `String`.
|
||||
|
||||
[1]: https://doc.rust-lang.org/std/string/struct.String.html
|
||||
[2]: https://doc.rust-lang.org/std/string/struct.String.html#deref-methods-str
|
||||
|
||||
<details>
|
||||
|
||||
* `String::new` returns a new empty string, use `String::with_capacity` when you know how much data you want to push to the string.
|
||||
* `String::len` returns the size of the `String` in bytes (which can be different from its length in characters).
|
||||
* `String::chars` returns an iterator over the actual characters. Note that a `char` can be different from what a human will consider a "character" due to [grapheme clusters](https://docs.rs/unicode-segmentation/latest/unicode_segmentation/struct.Graphemes.html).
|
||||
* When people refer to strings they could either be talking about `&str` or `String`.
|
||||
* When a type implements `Deref<Target = T>`, the compiler will let you transparently call methods from `T`.
|
||||
* We haven't discussed the `Deref` trait yet, so at this point this mostly explains the structure of the sidebar in the documentation.
|
||||
* `String` implements `Deref<Target = str>` which transparently gives it access to `str`'s methods.
|
||||
* Write and compare `let s3 = s1.deref();` and `let s3 = &*s1;`.
|
||||
* `String` is implemented as a wrapper around a vector of bytes, many of the operations you see supported on vectors are also supported on `String`, but with some extra guarantees.
|
||||
* Compare the different ways to index a `String`:
|
||||
* To a character by using `s3.chars().nth(i).unwrap()` where `i` is in-bound, out-of-bounds.
|
||||
* To a substring by using `s3[0..4]`, where that slice is on character boundaries or not.
|
||||
- `String::new` returns a new empty string, use `String::with_capacity` when you
|
||||
know how much data you want to push to the string.
|
||||
- `String::len` returns the size of the `String` in bytes (which can be
|
||||
different from its length in characters).
|
||||
- `String::chars` returns an iterator over the actual characters. Note that a
|
||||
`char` can be different from what a human will consider a "character" due to
|
||||
[grapheme clusters](https://docs.rs/unicode-segmentation/latest/unicode_segmentation/struct.Graphemes.html).
|
||||
- When people refer to strings they could either be talking about `&str` or
|
||||
`String`.
|
||||
- When a type implements `Deref<Target = T>`, the compiler will let you
|
||||
transparently call methods from `T`.
|
||||
- We haven't discussed the `Deref` trait yet, so at this point this mostly
|
||||
explains the structure of the sidebar in the documentation.
|
||||
- `String` implements `Deref<Target = str>` which transparently gives it
|
||||
access to `str`'s methods.
|
||||
- Write and compare `let s3 = s1.deref();` and `let s3 = &*s1;`.
|
||||
- `String` is implemented as a wrapper around a vector of bytes, many of the
|
||||
operations you see supported on vectors are also supported on `String`, but
|
||||
with some extra guarantees.
|
||||
- Compare the different ways to index a `String`:
|
||||
- To a character by using `s3.chars().nth(i).unwrap()` where `i` is in-bound,
|
||||
out-of-bounds.
|
||||
- To a substring by using `s3[0..4]`, where that slice is on character
|
||||
boundaries or not.
|
||||
|
||||
</details>
|
||||
|
@ -38,16 +38,18 @@ methods on a `Vec`.
|
||||
|
||||
<details>
|
||||
|
||||
* `Vec` is a type of collection, along with `String` and `HashMap`. The data it contains is stored
|
||||
on the heap. This means the amount of data doesn't need to be known at compile time. It can grow
|
||||
or shrink at runtime.
|
||||
* Notice how `Vec<T>` is a generic type too, but you don't have to specify `T` explicitly. As always
|
||||
with Rust type inference, the `T` was established during the first `push` call.
|
||||
* `vec![...]` is a canonical macro to use instead of `Vec::new()` and it supports adding initial
|
||||
elements to the vector.
|
||||
* To index the vector you use `[` `]`, but they will panic if out of bounds. Alternatively, using
|
||||
`get` will return an `Option`. The `pop` function will remove the last element.
|
||||
* Slices are covered on day 3. For now, students only need to know that a value
|
||||
- `Vec` is a type of collection, along with `String` and `HashMap`. The data it
|
||||
contains is stored on the heap. This means the amount of data doesn't need to
|
||||
be known at compile time. It can grow or shrink at runtime.
|
||||
- Notice how `Vec<T>` is a generic type too, but you don't have to specify `T`
|
||||
explicitly. As always with Rust type inference, the `T` was established during
|
||||
the first `push` call.
|
||||
- `vec![...]` is a canonical macro to use instead of `Vec::new()` and it
|
||||
supports adding initial elements to the vector.
|
||||
- To index the vector you use `[` `]`, but they will panic if out of bounds.
|
||||
Alternatively, using `get` will return an `Option`. The `pop` function will
|
||||
remove the last element.
|
||||
- Slices are covered on day 3. For now, students only need to know that a value
|
||||
of type `Vec` gives access to all of the documented slice methods, too.
|
||||
|
||||
</details>
|
||||
|
Reference in New Issue
Block a user