You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-15 22:00:26 +02:00
Various small fixes (#1556)
Plus one more substantial comment on casting.
This commit is contained in:
@ -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.
|
* 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.
|
* 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".
|
* 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."
|
* 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>
|
</details>
|
||||||
|
@ -62,4 +62,4 @@ Notes on stack returns:
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
[Playground]: https://play.rust-lang.org/
|
[Playground]: https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=0cb13be1c05d7e3446686ad9947c4671
|
||||||
|
@ -50,7 +50,7 @@ fn main() {
|
|||||||
<details>
|
<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`.
|
* 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.
|
* 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.
|
* A shadowing variable can have a different type.
|
||||||
* Shadowing looks obscure at first, but is convenient for holding on to values after `.unwrap()`.
|
* Shadowing looks obscure at first, but is convenient for holding on to values after `.unwrap()`.
|
||||||
|
@ -112,12 +112,12 @@ impl PackageBuilder {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let base64 = PackageBuilder::new("base64").version("0.13").build();
|
let base64 = PackageBuilder::new("base64").version("0.13").build();
|
||||||
println!("base64: {base64:?}");
|
println!("base64: {base64:?}");
|
||||||
let log = PackageBuilder::new("base64")
|
let log = PackageBuilder::new("log")
|
||||||
.version("0.4")
|
.version("0.4")
|
||||||
.language(Language::Rust)
|
.language(Language::Rust)
|
||||||
.build();
|
.build();
|
||||||
println!("log: {log:?}");
|
println!("log: {log:?}");
|
||||||
let serde = PackageBuilder::new("hawk")
|
let serde = PackageBuilder::new("serde")
|
||||||
.authors(vec!["djmitche".into()])
|
.authors(vec!["djmitche".into()])
|
||||||
.version(String::from("4.0"))
|
.version(String::from("4.0"))
|
||||||
.dependency(base64.as_dependency())
|
.dependency(base64.as_dependency())
|
||||||
|
@ -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.
|
* 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.
|
* 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>`.
|
* 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>
|
</details>
|
||||||
|
@ -33,6 +33,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# `let else` expressions
|
||||||
For the common case of matching a pattern and returning from the function, use
|
For the common case of matching a pattern and returning from the function, use
|
||||||
[`let
|
[`let
|
||||||
else`](https://doc.rust-lang.org/rust-by-example/flow_control/let_else.html).
|
else`](https://doc.rust-lang.org/rust-by-example/flow_control/let_else.html).
|
||||||
|
@ -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
|
popup (click the link with a little arrow next to "Speaker Notes"). This way
|
||||||
you have a clean screen to present to the class.
|
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
|
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
|
they find it helpful to have a gap in the course since it helps them process
|
||||||
all the information we give them.
|
all the information we give them.
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
## Rust Fundamentals
|
## 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!
|
The days are fast paced and we cover a lot of ground!
|
||||||
|
|
||||||
{{%course outline Fundamentals}}
|
{{%course outline Fundamentals}}
|
||||||
|
|
||||||
## Deep Dives
|
## 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:
|
specialized topics:
|
||||||
|
|
||||||
### Rust in Android
|
### Rust in Android
|
||||||
|
@ -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:
|
Try adjusting the signature to "lie" about the lifetimes returned:
|
||||||
|
|
||||||
```rust,ignore
|
```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
|
This won't compile, demonstrating that the annotations are checked for validity
|
||||||
|
@ -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
|
* 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.
|
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>
|
</details>
|
||||||
|
@ -37,6 +37,6 @@ fn main() {
|
|||||||
* Use `Rc::strong_count` to check the reference count.
|
* Use `Rc::strong_count` to check the reference count.
|
||||||
* `Rc::downgrade` gives you a *weakly reference-counted* object to
|
* `Rc::downgrade` gives you a *weakly reference-counted* object to
|
||||||
create cycles that will be dropped properly (likely in combination with
|
create cycles that will be dropped properly (likely in combination with
|
||||||
`RefCell`, on the next slide).
|
`RefCell`).
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
@ -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
|
platforms. This might not match your intuition for changing sign or casting to
|
||||||
a smaller type -- check the docs, and comment for clarity.
|
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>
|
<details>
|
||||||
|
|
||||||
Consider taking a break after this slide.
|
Consider taking a break after this slide.
|
||||||
|
@ -45,9 +45,9 @@ fn main() {
|
|||||||
* A derived implementation will produce a value where all fields are set to their default values.
|
* 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.
|
* This means all types in the struct must implement `Default` too.
|
||||||
* Standard Rust types often implement `Default` with reasonable values (e.g. `0`, `""`, etc).
|
* Standard Rust types often implement `Default` with reasonable values (e.g. `0`, `""`, etc).
|
||||||
* The partial struct copy works nicely with default.
|
* The partial struct initialization works nicely with default.
|
||||||
* Rust standard library is aware that types can implement `Default` and provides convenience methods that use it.
|
* 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]
|
* The `..` syntax is called [struct update syntax][2].
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ fn main() {
|
|||||||
let s = String::from("hello");
|
let s = String::from("hello");
|
||||||
let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);
|
let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);
|
||||||
let one = i16::from(true);
|
let one = i16::from(true);
|
||||||
let bigger = i32::from(123i16);
|
let bigger = i32::from(123_i16);
|
||||||
println!("{s}, {addr}, {one}, {bigger}");
|
println!("{s}, {addr}, {one}, {bigger}");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -23,7 +23,7 @@ fn main() {
|
|||||||
let s: String = "hello".into();
|
let s: String = "hello".into();
|
||||||
let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();
|
let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();
|
||||||
let one: i16 = true.into();
|
let one: i16 = true.into();
|
||||||
let bigger: i32 = 123i16.into();
|
let bigger: i32 = 123_i16.into();
|
||||||
println!("{s}, {addr}, {one}, {bigger}");
|
println!("{s}, {addr}, {one}, {bigger}");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -68,9 +68,6 @@ Key Points:
|
|||||||
|
|
||||||
Rust has several optimizations it can employ to make enums take up less space.
|
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
|
* Null pointer optimization: For [some
|
||||||
types](https://doc.rust-lang.org/std/option/#representation), Rust guarantees
|
types](https://doc.rust-lang.org/std/option/#representation), Rust guarantees
|
||||||
that `size_of::<T>()` equals `size_of::<Option<T>>()`.
|
that `size_of::<T>()` equals `size_of::<Option<T>>()`.
|
||||||
|
@ -51,6 +51,6 @@ Key Points:
|
|||||||
* The next slide will introduce Tuple structs, used when the field names are not important.
|
* 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
|
* If you already have variables with the right names, then you can create the
|
||||||
struct using a shorthand.
|
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>
|
</details>
|
||||||
|
Reference in New Issue
Block a user