You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-12-22 22:51:12 +02:00
Move slices and strings to references section (#1898)
This PR moves the slides for slices and strings into the day 1 section on references. This seems like the more natural place to introduce slices since slices are a type of reference. It then also made sense to me to follow that with the introduction of `&str` and `String`, since students now have the context to understand what a "string slice" is. I also removed the strings slide from the types and values section since it didn't make sense to cover the same topic twice in the same day. I tested this new organization in my class on Wednesday and it didn't cause day 1 to take too long.
This commit is contained in:
52
src/references/slices.md
Normal file
52
src/references/slices.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
minutes: 10
|
||||
---
|
||||
|
||||
# Slices
|
||||
|
||||
A slice gives you a view into a larger collection:
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
|
||||
```rust,editable
|
||||
fn main() {
|
||||
let mut a: [i32; 6] = [10, 20, 30, 40, 50, 60];
|
||||
println!("a: {a:?}");
|
||||
|
||||
let s: &[i32] = &a[2..4];
|
||||
|
||||
println!("s: {s:?}");
|
||||
}
|
||||
```
|
||||
|
||||
- Slices borrow data from the sliced type.
|
||||
- Question: What happens if you modify `a[3]` right before printing `s`?
|
||||
|
||||
<details>
|
||||
|
||||
- We create a slice by borrowing `a` and specifying the starting and ending
|
||||
indexes in brackets.
|
||||
|
||||
- If the slice starts at index 0, Rust’s range syntax allows us to drop the
|
||||
starting index, meaning that `&a[0..a.len()]` and `&a[..a.len()]` are
|
||||
identical.
|
||||
|
||||
- The same is true for the last index, so `&a[2..a.len()]` and `&a[2..]` are
|
||||
identical.
|
||||
|
||||
- To easily create a slice of the full array, we can therefore use `&a[..]`.
|
||||
|
||||
- `s` is a reference to a slice of `i32`s. Notice that the type of `s`
|
||||
(`&[i32]`) no longer mentions the array length. This allows us to perform
|
||||
computation on slices of different sizes.
|
||||
|
||||
- Slices always borrow from another object. In this example, `a` has to remain
|
||||
'alive' (in scope) for at least as long as our slice.
|
||||
|
||||
- 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.
|
||||
|
||||
</details>
|
||||
79
src/references/strings.md
Normal file
79
src/references/strings.md
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
minutes: 10
|
||||
---
|
||||
|
||||
<!-- NOTES:
|
||||
Including `&str` as a way of representing a slice of valid utf-8
|
||||
-->
|
||||
|
||||
# Strings
|
||||
|
||||
We can now understand the two string types in Rust:
|
||||
|
||||
- `&str` is a slice of UTF-8 encoded bytes, similar to `&[u8]`.
|
||||
- `String` is an owned, heap-allocated buffer of UTF-8 bytes.
|
||||
|
||||
```rust,editable
|
||||
fn main() {
|
||||
let s1: &str = "World";
|
||||
println!("s1: {s1}");
|
||||
|
||||
let mut s2: String = String::from("Hello ");
|
||||
println!("s2: {s2}");
|
||||
s2.push_str(s1);
|
||||
println!("s2: {s2}");
|
||||
|
||||
let s3: &str = &s2[6..];
|
||||
println!("s3: {s3}");
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
- `&str` introduces a string slice, which is an immutable reference to UTF-8
|
||||
encoded string data stored in a block of memory. String literals (`"Hello"`),
|
||||
are stored in the program’s binary.
|
||||
|
||||
- Rust's `String` type is a wrapper around a vector of bytes. As with a
|
||||
`Vec<T>`, it is owned.
|
||||
|
||||
- As with many other types `String::from()` creates a string from a string
|
||||
literal; `String::new()` creates a new empty string, to which string data can
|
||||
be added using the `push()` and `push_str()` methods.
|
||||
|
||||
- The `format!()` macro is a convenient way to generate an owned string from
|
||||
dynamic values. It accepts the same format specification as `println!()`.
|
||||
|
||||
- You can borrow `&str` slices from `String` via `&` and optionally range
|
||||
selection. If you select a byte range that is not aligned to character
|
||||
boundaries, the expression will panic. The `chars` iterator iterates over
|
||||
characters and is preferred over trying to get character boundaries right.
|
||||
|
||||
- For C++ programmers: think of `&str` as `std::string_view` from C++, but the
|
||||
one that always points to a valid string in memory. Rust `String` is a rough
|
||||
equivalent of `std::string` from C++ (main difference: it can only contain
|
||||
UTF-8 encoded bytes and will never use a small-string optimization).
|
||||
|
||||
- Byte strings literals allow you to create a `&[u8]` value directly:
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
```rust,editable
|
||||
fn main() {
|
||||
println!("{:?}", b"abc");
|
||||
println!("{:?}", &[97, 98, 99]);
|
||||
}
|
||||
```
|
||||
|
||||
- Raw strings allow you to create a `&str` value with escapes disabled:
|
||||
`r"\n" == "\\n"`. You can embed double-quotes by using an equal amount of `#`
|
||||
on either side of the quotes:
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
```rust,editable
|
||||
fn main() {
|
||||
println!(r#"<a href="link.html">link</a>"#);
|
||||
println!("<a href=\"link.html\">link</a>");
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
Reference in New Issue
Block a user