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:
parent
8f9902cc3e
commit
6c5061bb90
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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()`.
|
||||
|
@ -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())
|
||||
|
@ -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>
|
||||
|
@ -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).
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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}");
|
||||
}
|
||||
```
|
||||
|
@ -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>>()`.
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user