1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2024-12-15 06:20:32 +02:00

Various small fixes (#1556)

Plus one more substantial comment on casting.
This commit is contained in:
Marshall Pierce 2023-12-05 16:06:42 -07:00 committed by GitHub
parent 8f9902cc3e
commit 6c5061bb90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 23 additions and 21 deletions

View File

@ -31,7 +31,7 @@ fn main() {
* The above code does not compile because `a` is borrowed as mutable (through `c`) and as immutable (through `b`) at the same time.
* Move the `println!` statement for `b` before the scope that introduces `c` to make the code compile.
* After that change, the compiler realizes that `b` is only ever used before the new mutable borrow of `a` through `c`. This is a feature of the borrow checker called "non-lexical lifetimes".
* The exclusive reference constraint is quite strong. Rust uses it to ensure that data races do not occur. Rust also _relies_ on this constraint to optimize codes. For example, a value behind a shared reference can be safely cached in a register for the lifetime of that reference.
* The exclusive reference constraint is quite strong. Rust uses it to ensure that data races do not occur. Rust also _relies_ on this constraint to optimize code. For example, a value behind a shared reference can be safely cached in a register for the lifetime of that reference.
* The borrow checker is designed to accommodate many common patterns, such as taking exclusive references to different fields in a struct at the same time. But, there are some situations where it doesn't quite "get it" and this often results in "fighting with the borrow checker."
</details>

View File

@ -62,4 +62,4 @@ Notes on stack returns:
</details>
[Playground]: https://play.rust-lang.org/
[Playground]: https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=0cb13be1c05d7e3446686ad9947c4671

View File

@ -50,7 +50,7 @@ fn main() {
<details>
* You can show how the value of the block changes by changing the last line in the block. For instance, adding/removing a semicolon or using a `return`.
* Show that a variable's scope is limited by adding a b` in the inner block in the last example, and then trying to access it outside that block.
* Show that a variable's scope is limited by adding a `b` in the inner block in the last example, and then trying to access it outside that block.
* Shadowing is different from mutation, because after shadowing both variable's memory locations exist at the same time. Both are available under the same name, depending where you use it in the code.
* A shadowing variable can have a different type.
* Shadowing looks obscure at first, but is convenient for holding on to values after `.unwrap()`.

View File

@ -112,12 +112,12 @@ impl PackageBuilder {
fn main() {
let base64 = PackageBuilder::new("base64").version("0.13").build();
println!("base64: {base64:?}");
let log = PackageBuilder::new("base64")
let log = PackageBuilder::new("log")
.version("0.4")
.language(Language::Rust)
.build();
println!("log: {log:?}");
let serde = PackageBuilder::new("hawk")
let serde = PackageBuilder::new("serde")
.authors(vec!["djmitche".into()])
.version(String::from("4.0"))
.dependency(base64.as_dependency())

View File

@ -75,6 +75,5 @@ Key Points:
* Note how `self` is used like other structs and dot notation can be used to refer to individual fields.
* This might be a good time to demonstrate how the `&self` differs from `self` by trying to run `finish` twice.
* Beyond variants on `self`, there are also [special wrapper types](https://doc.rust-lang.org/reference/special-types-and-traits.html) allowed to be receiver types, such as `Box<Self>`.
* Note that references have not been covered yet. References in method receivers are a particularly "natural" form of reference, so there is no need to go into a great level of detail.
</details>

View File

@ -33,6 +33,7 @@ fn main() {
}
```
# `let else` expressions
For the common case of matching a pattern and returning from the function, use
[`let
else`](https://doc.rust-lang.org/rust-by-example/flow_control/let_else.html).

View File

@ -18,7 +18,7 @@ Before you run the course, you will want to:
popup (click the link with a little arrow next to "Speaker Notes"). This way
you have a clean screen to present to the class.
1. Decide on the dates. Since the course takes at least three full days, we recommend that you
1. Decide on the dates. Since the course takes four days, we recommend that you
schedule the days over two weeks. Course participants have said that
they find it helpful to have a gap in the course since it helps them process
all the information we give them.

View File

@ -4,14 +4,14 @@
## Rust Fundamentals
The first three days make up [Rust Fundaments](../welcome-day-1.md).
The first four days make up [Rust Fundaments](../welcome-day-1.md).
The days are fast paced and we cover a lot of ground!
{{%course outline Fundamentals}}
## Deep Dives
In addition to the 3-day class on Rust Fundamentals, we cover some more
In addition to the 4-day class on Rust Fundamentals, we cover some more
specialized topics:
### Rust in Android

View File

@ -57,7 +57,7 @@ The `nearest` function provides another example of a function with multiple refe
Try adjusting the signature to "lie" about the lifetimes returned:
```rust,ignore
fn nearest<'a>(points: &'a [Point], query: &'q Point) -> Option<&'q Point> {
fn nearest<'a, 'q'>(points: &'a [Point], query: &'q Point) -> Option<&'q Point> {
```
This won't compile, demonstrating that the annotations are checked for validity

View File

@ -37,6 +37,6 @@ fn main() {
* The question about modifying `a[3]` can spark an interesting discussion, but the answer is that for memory safety reasons
you cannot do it through `a` at this point in the execution, but you can read the data from both `a` and `s` safely.
It works before you created the slice, and again after the `println`, when the slice is no longer used. More details will be explained in the borrow checker section.
It works before you created the slice, and again after the `println`, when the slice is no longer used.
</details>

View File

@ -37,6 +37,6 @@ fn main() {
* Use `Rc::strong_count` to check the reference count.
* `Rc::downgrade` gives you a *weakly reference-counted* object to
create cycles that will be dropped properly (likely in combination with
`RefCell`, on the next slide).
`RefCell`).
</details>

View File

@ -20,6 +20,11 @@ The results of `as` are _always_ defined in Rust and consistent across
platforms. This might not match your intuition for changing sign or casting to
a smaller type -- check the docs, and comment for clarity.
Casting with `as` is a relatively sharp tool that is easy to use incorrectly, and can be a source of subtle bugs as future maintenance work changes the types that are used or the ranges of values in types. Casts are best used only when the intent is to indicate unconditional truncation (e.g. selecting the bottom 32 bits of a `u64` with `as u32`, regardless of what was in the high bits).
For infallible casts (e.g. `u32` to `u64`), prefer using `From` or `Into` over `as`
to confirm that the cast is in fact infallible. For fallible casts, `TryFrom` and `TryInto` are available when you want to handle casts that fit differently from those that don't.
<details>
Consider taking a break after this slide.

View File

@ -45,9 +45,9 @@ fn main() {
* A derived implementation will produce a value where all fields are set to their default values.
* This means all types in the struct must implement `Default` too.
* Standard Rust types often implement `Default` with reasonable values (e.g. `0`, `""`, etc).
* The partial struct copy works nicely with default.
* Rust standard library is aware that types can implement `Default` and provides convenience methods that use it.
* the `..` syntax is called [struct update syntax][2]
* The partial struct initialization works nicely with default.
* The Rust standard library is aware that types can implement `Default` and provides convenience methods that use it.
* The `..` syntax is called [struct update syntax][2].
</details>

View File

@ -11,7 +11,7 @@ fn main() {
let s = String::from("hello");
let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);
let one = i16::from(true);
let bigger = i32::from(123i16);
let bigger = i32::from(123_i16);
println!("{s}, {addr}, {one}, {bigger}");
}
```
@ -23,7 +23,7 @@ fn main() {
let s: String = "hello".into();
let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();
let one: i16 = true.into();
let bigger: i32 = 123i16.into();
let bigger: i32 = 123_i16.into();
println!("{s}, {addr}, {one}, {bigger}");
}
```

View File

@ -68,9 +68,6 @@ Key Points:
Rust has several optimizations it can employ to make enums take up less space.
* Niche optimization: Rust will merge unused bit patterns for the enum
discriminant.
* Null pointer optimization: For [some
types](https://doc.rust-lang.org/std/option/#representation), Rust guarantees
that `size_of::<T>()` equals `size_of::<Option<T>>()`.

View File

@ -51,6 +51,6 @@ Key Points:
* The next slide will introduce Tuple structs, used when the field names are not important.
* If you already have variables with the right names, then you can create the
struct using a shorthand.
* The syntax `..peter` allows us to copy the majority of the fields from the old struct without having to explicitly type it all out. It must always be the last element.
* The syntax `..avery` allows us to copy the majority of the fields from the old struct without having to explicitly type it all out. It must always be the last element.
</details>