1
0
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:
Nicole L
2024-03-14 13:21:15 -07:00
committed by GitHub
parent 4b27e28e7f
commit 7cd25c0262
15 changed files with 46 additions and 88 deletions

52
src/references/slices.md Normal file
View 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
View 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>