Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
// ANCHOR: here
{ // s is not valid here, it’s not yet declared
{ // s is not valid here, since it's not yet declared
let s = "hello"; // s is valid from this point forward

// do stuff with s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ fn main() {

let x = 5; // x comes into scope

makes_copy(x); // because i32 implements the Copy trait,
makes_copy(x); // Because i32 implements the Copy trait,
// x does NOT move into the function,
println!("{}", x); // so it's okay to use x afterward
// so it's okay to use x afterward.

} // Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
} // Here, x goes out of scope, then s. However, because s's value was moved,
// nothing special happens.

fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{some_string}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ fn main() {

s.clear(); // this empties the String, making it equal to ""

// `word` still has the value `5` here, but `s` no longer has any content
// that we could meaningfully use with the value `5`, so `word` is now
// totally invalid!
// word still has the value 5 here, but s no longer has any content that we
// could meaningfully use with the value 5, so word is now totally invalid!
}
// ANCHOR_END: here
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ fn main() {

s.push_str(", world!"); // push_str() appends a literal to a String

println!("{s}"); // This will print `hello, world!`
println!("{s}"); // this will print `hello, world!`
// ANCHOR_END: here
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ fn main() {
fn calculate_length(s: &String) -> usize { // s is a reference to a String
s.len()
} // Here, s goes out of scope. But because s does not have ownership of what
// it refers to, the value is not dropped.
// it refers to, the String is not dropped.
// ANCHOR_END: here
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ error[E0499]: cannot borrow `s` as mutable more than once at a time
5 | let r2 = &mut s;
| ^^^^^^ second mutable borrow occurs here
6 |
7 | println!("{}, {}", r1, r2);
| -- first borrow later used here
7 | println!("{r1}, {r2}");
| ---- first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `ownership` (bin "ownership") due to 1 previous error
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ fn main() {
let r1 = &mut s;
let r2 = &mut s;

println!("{}, {}", r1, r2);
println!("{r1}, {r2}");
// ANCHOR_END: here
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immuta
6 | let r3 = &mut s; // BIG PROBLEM
| ^^^^^^ mutable borrow occurs here
7 |
8 | println!("{}, {}, and {}", r1, r2, r3);
| -- immutable borrow later used here
8 | println!("{r1}, {r2}, and {r3}");
| ---- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` (bin "ownership") due to 1 previous error
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ fn main() {
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM

println!("{}, {}, and {}", r1, r2, r3);
println!("{r1}, {r2}, and {r3}");
// ANCHOR_END: here
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ fn dangle() -> &String { // dangle returns a reference to a String
let s = String::from("hello"); // s is a new String

&s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped, so its memory goes away.
} // Here, s goes out of scope and is dropped, so its memory goes away.
// Danger!
// ANCHOR_END: here
70 changes: 36 additions & 34 deletions nostarch/chapter04.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ strings.
> to hold the data and then perform bookkeeping to prepare for the next
> allocation.
>
> Accessing data in the heap is slower than accessing data on the stack because
> you have to follow a pointer to get there. Contemporary processors are faster
> if they jump around less in memory. Continuing the analogy, consider a server
> at a restaurant taking orders from many tables. It’s most efficient to get
> all the orders at one table before moving on to the next table. Taking an
> order from table A, then an order from table B, then one from A again, and
> then one from B again would be a much slower process. By the same token, a
> processor can do its job better if it works on data that’s close to other
> data (as it is on the stack) rather than farther away (as it can be on the
> heap).
> Accessing data in the heap is generally slower than accessing data on the
> stack because you have to follow a pointer to get there. Contemporary
> processors are faster if they jump around less in memory. Continuing the
> analogy, consider a server at a restaurant taking orders from many tables.
> It’s most efficient to get all the orders at one table before moving on to
> the next table. Taking an order from table A, then an order from table B,
> then one from A again, and then one from B again would be a much slower
> process. By the same token, a processor can usually do its job better if it
> works on data that’s close to other data (as it is on the stack) rather than
> farther away (as it can be on the heap).
>
> When your code calls a function, the values passed into the function
> (including, potentially, pointers to data on the heap) and the function’s
Expand Down Expand Up @@ -131,7 +131,7 @@ program with comments annotating where the variable `s` would be valid.


```
{ // s is not valid here, it’s not yet declared
{ // s is not valid here, since it's not yet declared
let s = "hello"; // s is valid from this point forward

// do stuff with s
Expand Down Expand Up @@ -193,7 +193,7 @@ This kind of string *can* be mutated:

s.push_str(", world!"); // push_str() appends a literal to a String

println!("{s}"); // This will print `hello, world!`
println!("{s}"); // this will print `hello, world!`
```

So, what’s the difference here? Why can `String` be mutated but literals
Expand Down Expand Up @@ -536,12 +536,12 @@ fn main() {

let x = 5; // x comes into scope

makes_copy(x); // because i32 implements the Copy trait,
makes_copy(x); // Because i32 implements the Copy trait,
// x does NOT move into the function,
println!("{}", x); // so it's okay to use x afterward
// so it's okay to use x afterward.

} // Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
} // Here, x goes out of scope, then s. However, because s's value was moved,
// nothing special happens.

fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{some_string}");
Expand Down Expand Up @@ -708,7 +708,7 @@ the parameter `s` is a reference. Let’s add some explanatory annotations:
fn calculate_length(s: &String) -> usize { // s is a reference to a String
s.len()
} // Here, s goes out of scope. But because s does not have ownership of what
// it refers to, the value is not dropped.
// it refers to, the String is not dropped.
```

The scope in which the variable `s` is valid is the same as any function
Expand Down Expand Up @@ -801,7 +801,7 @@ src/main.rs
let r1 = &mut s;
let r2 = &mut s;

println!("{}, {}", r1, r2);
println!("{r1}, {r2}");
```


Expand Down Expand Up @@ -870,7 +870,7 @@ This code results in an error:
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM

println!("{}, {}, and {}", r1, r2, r3);
println!("{r1}, {r2}, and {r3}");
```

Here’s the error:
Expand Down Expand Up @@ -1012,7 +1012,7 @@ fn dangle() -> &String { // dangle returns a reference to a String
let s = String::from("hello"); // s is a new String

&s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped, so its memory goes away.
} // Here, s goes out of scope and is dropped, so its memory goes away.
// Danger!
```

Expand Down Expand Up @@ -1049,27 +1049,32 @@ Next, we’ll look at a different kind of reference: slices.
## The Slice Type

*Slices* let you reference a contiguous sequence of elements in a
collection at *ch08-00-common-collections.md* rather than the whole collection. A
slice is a kind of reference, so it does not have ownership.
collection. A slice is a kind
of reference, so it does not have ownership.

Here’s a small programming problem: write a function that takes a string of
words separated by spaces and returns the first word it finds in that string.
If the function doesn’t find a space in the string, the whole string must be
one word, so the entire string should be returned.

> Note: For the purposes of introducing string slices, we are assuming ASCII
> only in this section; a more thorough discussion of UTF-8 handling is in the
> “Storing UTF-8 Encoded Text with Strings” section
> of Chapter 8.

Let’s work through how we’d write the signature of this function without using
slices, to understand the problem that slices will solve:

```
fn first_word(s: &String) -> ?
```

The `first_word` function has a `&String` as a parameter. We don’t need
The `first_word` function has a parameter of type `&String`. We don’t need
ownership, so this is fine. (In idiomatic Rust, functions do not take ownership
of their arguments unless they need to, and the reasons for that will become
clear as we keep going!) But what should we return? We don’t really have a way
to talk about part of a string. However, we could return the index of the end of
the word, indicated by a space. Let’s try that, as shown in Listing 4-7.
clear as we keep going.) But what should we return? We don’t really have a way
to talk about *part* of a string. However, we could return the index of the end
of the word, indicated by a space. Let’s try that, as shown in Listing 4-7.

src/main.rs

Expand Down Expand Up @@ -1147,9 +1152,8 @@ fn main() {

s.clear(); // this empties the String, making it equal to ""

// `word` still has the value `5` here, but `s` no longer has any content
// that we could meaningfully use with the value `5`, so `word` is now
// totally invalid!
// word still has the value 5 here, but s no longer has any content that we
// could meaningfully use with the value 5, so word is now totally invalid!
}
```

Expand Down Expand Up @@ -1178,7 +1182,8 @@ Luckily, Rust has a solution to this problem: string slices.

### String Slices

A *string slice* is a reference to part of a `String`, and it looks like this:
A *string slice* is a reference to a contiguous sequence of the elements of a
`String`, and it looks like this:

```
let s = String::from("hello world");
Expand Down Expand Up @@ -1243,10 +1248,7 @@ let slice = &s[..];

> Note: String slice range indices must occur at valid UTF-8 character
> boundaries. If you attempt to create a string slice in the middle of a
> multibyte character, your program will exit with an error. For the purposes
> of introducing string slices, we are assuming ASCII only in this section; a
> more thorough discussion of UTF-8 handling is in the “Storing UTF-8 Encoded
> Text with Strings” section of Chapter 8.
> multibyte character, your program will exit with an error.

With all this information in mind, let’s rewrite `first_word` to return a
slice. The type that signifies “string slice” is written as `&str`:
Expand Down
Binary file modified nostarch/docx/chapter04.docx
Binary file not shown.
20 changes: 10 additions & 10 deletions src/ch04-01-what-is-ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@ strings.
> to hold the data and then perform bookkeeping to prepare for the next
> allocation.
>
> Accessing data in the heap is slower than accessing data on the stack because
> you have to follow a pointer to get there. Contemporary processors are faster
> if they jump around less in memory. Continuing the analogy, consider a server
> at a restaurant taking orders from many tables. It’s most efficient to get
> all the orders at one table before moving on to the next table. Taking an
> order from table A, then an order from table B, then one from A again, and
> then one from B again would be a much slower process. By the same token, a
> processor can do its job better if it works on data that’s close to other
> data (as it is on the stack) rather than farther away (as it can be on the
> heap).
> Accessing data in the heap is generally slower than accessing data on the
> stack because you have to follow a pointer to get there. Contemporary
> processors are faster if they jump around less in memory. Continuing the
> analogy, consider a server at a restaurant taking orders from many tables.
> It’s most efficient to get all the orders at one table before moving on to
> the next table. Taking an order from table A, then an order from table B,
> then one from A again, and then one from B again would be a much slower
> process. By the same token, a processor can usually do its job better if it
> works on data that’s close to other data (as it is on the stack) rather than
> farther away (as it can be on the heap).
>
> When your code calls a function, the values passed into the function
> (including, potentially, pointers to data on the heap) and the function’s
Expand Down
25 changes: 14 additions & 11 deletions src/ch04-03-slices.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
## The Slice Type

_Slices_ let you reference a contiguous sequence of elements in a
[collection](ch08-00-common-collections.md) rather than the whole collection. A
slice is a kind of reference, so it does not have ownership.
[collection](ch08-00-common-collections.md)<!-- ignore -->. A slice is a kind
of reference, so it does not have ownership.

Here’s a small programming problem: write a function that takes a string of
words separated by spaces and returns the first word it finds in that string.
If the function doesn’t find a space in the string, the whole string must be
one word, so the entire string should be returned.

> Note: For the purposes of introducing string slices, we are assuming ASCII
> only in this section; a more thorough discussion of UTF-8 handling is in the
> [“Storing UTF-8 Encoded Text with Strings”][strings]<!-- ignore --> section
> of Chapter 8.

Let’s work through how we’d write the signature of this function without using
slices, to understand the problem that slices will solve:

```rust,ignore
fn first_word(s: &String) -> ?
```

The `first_word` function has a `&String` as a parameter. We don’t need
The `first_word` function has a parameter of type `&String`. We don’t need
ownership, so this is fine. (In idiomatic Rust, functions do not take ownership
of their arguments unless they need to, and the reasons for that will become
clear as we keep going!) But what should we return? We don’t really have a way
to talk about part of a string. However, we could return the index of the end of
the word, indicated by a space. Let’s try that, as shown in Listing 4-7.
clear as we keep going.) But what should we return? We don’t really have a way
to talk about *part* of a string. However, we could return the index of the end
of the word, indicated by a space. Let’s try that, as shown in Listing 4-7.

<Listing number="4-7" file-name="src/main.rs" caption="The `first_word` function that returns a byte index value into the `String` parameter">

Expand Down Expand Up @@ -105,7 +110,8 @@ Luckily, Rust has a solution to this problem: string slices.

### String Slices

A _string slice_ is a reference to part of a `String`, and it looks like this:
A _string slice_ is a reference to a contiguous sequence of the elements of a
`String`, and it looks like this:

```rust
{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-17-slice/src/main.rs:here}}
Expand Down Expand Up @@ -168,10 +174,7 @@ let slice = &s[..];

> Note: String slice range indices must occur at valid UTF-8 character
> boundaries. If you attempt to create a string slice in the middle of a
> multibyte character, your program will exit with an error. For the purposes
> of introducing string slices, we are assuming ASCII only in this section; a
> more thorough discussion of UTF-8 handling is in the [“Storing UTF-8 Encoded
> Text with Strings”][strings]<!-- ignore --> section of Chapter 8.
> multibyte character, your program will exit with an error.

With all this information in mind, let’s rewrite `first_word` to return a
slice. The type that signifies “string slice” is written as `&str`:
Expand Down