353 lines
17 KiB
HTML
353 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>References and Borrowing</title>
|
||
</head>
|
||
<body>
|
||
<h2 id="references-and-borrowing"><a class="header" href="#references-and-borrowing">References and Borrowing</a></h2>
|
||
<p>The issue with the tuple code in Listing 4-5 is that we have to return the
|
||
<code>String</code> to the calling function so that we can still use the <code>String</code> after
|
||
the call to <code>calculate_length</code>, because the <code>String</code> was moved into
|
||
<code>calculate_length</code>. Instead, we can provide a reference to the <code>String</code> value.
|
||
A reference is like a pointer in that it’s an address we can follow to access
|
||
the data stored at that address; that data is owned by some other variable.
|
||
Unlike a pointer, a reference is guaranteed to point to a valid value of a
|
||
particular type for the life of that reference.</p>
|
||
<p>Here is how you would define and use a <code>calculate_length</code> function that has a
|
||
reference to an object as a parameter instead of taking ownership of the value:</p>
|
||
<figure class="listing">
|
||
<span class="file-name">Filename: src/main.rs</span>
|
||
<pre class="playground"><code class="language-rust edition2024">fn main() {
|
||
let s1 = String::from("hello");
|
||
|
||
let len = calculate_length(&s1);
|
||
|
||
println!("The length of '{s1}' is {len}.");
|
||
}
|
||
|
||
fn calculate_length(s: &String) -> usize {
|
||
s.len()
|
||
}</code></pre>
|
||
</figure>
|
||
<p>First, notice that all the tuple code in the variable declaration and the
|
||
function return value is gone. Second, note that we pass <code>&s1</code> into
|
||
<code>calculate_length</code> and, in its definition, we take <code>&String</code> rather than
|
||
<code>String</code>. These ampersands represent references, and they allow you to refer to
|
||
some value without taking ownership of it. Figure 4-6 depicts this concept.</p>
|
||
<p><img alt="Three tables: the table for s contains only a pointer to the table
|
||
for s1. The table for s1 contains the stack data for s1 and points to the
|
||
string data on the heap." src="../img/trpl04-06.svg" class="center" /></p>
|
||
<p><span class="caption">Figure 4-6: A diagram of <code>&String</code> <code>s</code> pointing at
|
||
<code>String</code> <code>s1</code></span></p>
|
||
<section class="note" aria-role="note">
|
||
<p>Note: The opposite of referencing by using <code>&</code> is <em>dereferencing</em>, which is
|
||
accomplished with the dereference operator, <code>*</code>. We’ll see some uses of the
|
||
dereference operator in Chapter 8 and discuss details of dereferencing in
|
||
Chapter 15.</p>
|
||
</section>
|
||
<p>Let’s take a closer look at the function call here:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span> let s1 = String::from("hello");
|
||
|
||
let len = calculate_length(&s1);
|
||
<span class="boring">
|
||
</span><span class="boring"> println!("The length of '{s1}' is {len}.");
|
||
</span><span class="boring">}
|
||
</span><span class="boring">
|
||
</span><span class="boring">fn calculate_length(s: &String) -> usize {
|
||
</span><span class="boring"> s.len()
|
||
</span><span class="boring">}</span></code></pre>
|
||
<p>The <code>&s1</code> syntax lets us create a reference that <em>refers</em> to the value of <code>s1</code>
|
||
but does not own it. Because the reference does not own it, the value it points
|
||
to will not be dropped when the reference stops being used.</p>
|
||
<p>Likewise, the signature of the function uses <code>&</code> to indicate that the type of
|
||
the parameter <code>s</code> is a reference. Let’s add some explanatory annotations:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span><span class="boring"> let s1 = String::from("hello");
|
||
</span><span class="boring">
|
||
</span><span class="boring"> let len = calculate_length(&s1);
|
||
</span><span class="boring">
|
||
</span><span class="boring"> println!("The length of '{s1}' is {len}.");
|
||
</span><span class="boring">}
|
||
</span><span class="boring">
|
||
</span>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 String is not dropped.</code></pre>
|
||
<p>The scope in which the variable <code>s</code> is valid is the same as any function
|
||
parameter’s scope, but the value pointed to by the reference is not dropped
|
||
when <code>s</code> stops being used, because <code>s</code> doesn’t have ownership. When functions
|
||
have references as parameters instead of the actual values, we won’t need to
|
||
return the values in order to give back ownership, because we never had
|
||
ownership.</p>
|
||
<p>We call the action of creating a reference <em>borrowing</em>. As in real life, if a
|
||
person owns something, you can borrow it from them. When you’re done, you have
|
||
to give it back. You don’t own it.</p>
|
||
<p>So, what happens if we try to modify something we’re borrowing? Try the code in
|
||
Listing 4-6. Spoiler alert: It doesn’t work!</p>
|
||
<figure class="listing" id="listing-4-6">
|
||
<span class="file-name">Filename: src/main.rs</span>
|
||
<pre><code class="language-rust ignore does_not_compile">fn main() {
|
||
let s = String::from("hello");
|
||
|
||
change(&s);
|
||
}
|
||
|
||
fn change(some_string: &String) {
|
||
some_string.push_str(", world");
|
||
}</code></pre>
|
||
<figcaption><a href="#listing-4-6">Listing 4-6</a>: Attempting to modify a borrowed value</figcaption>
|
||
</figure>
|
||
<p>Here’s the error:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling ownership v0.1.0 (file:///projects/ownership)
|
||
error[E0596]: cannot borrow `*some_string` as mutable, as it is behind a `&` reference
|
||
--> src/main.rs:8:5
|
||
|
|
||
8 | some_string.push_str(", world");
|
||
| ^^^^^^^^^^^ `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
||
|
|
||
help: consider changing this to be a mutable reference
|
||
|
|
||
7 | fn change(some_string: &mut String) {
|
||
| +++
|
||
|
||
For more information about this error, try `rustc --explain E0596`.
|
||
error: could not compile `ownership` (bin "ownership") due to 1 previous error
|
||
</code></pre>
|
||
<p>Just as variables are immutable by default, so are references. We’re not
|
||
allowed to modify something we have a reference to.</p>
|
||
<h3 id="mutable-references"><a class="header" href="#mutable-references">Mutable References</a></h3>
|
||
<p>We can fix the code from Listing 4-6 to allow us to modify a borrowed value
|
||
with just a few small tweaks that use, instead, a <em>mutable reference</em>:</p>
|
||
<figure class="listing">
|
||
<span class="file-name">Filename: src/main.rs</span>
|
||
<pre class="playground"><code class="language-rust edition2024">fn main() {
|
||
let mut s = String::from("hello");
|
||
|
||
change(&mut s);
|
||
}
|
||
|
||
fn change(some_string: &mut String) {
|
||
some_string.push_str(", world");
|
||
}</code></pre>
|
||
</figure>
|
||
<p>First, we change <code>s</code> to be <code>mut</code>. Then, we create a mutable reference with
|
||
<code>&mut s</code> where we call the <code>change</code> function and update the function signature
|
||
to accept a mutable reference with <code>some_string: &mut String</code>. This makes it
|
||
very clear that the <code>change</code> function will mutate the value it borrows.</p>
|
||
<p>Mutable references have one big restriction: If you have a mutable reference to
|
||
a value, you can have no other references to that value. This code that
|
||
attempts to create two mutable references to <code>s</code> will fail:</p>
|
||
<figure class="listing">
|
||
<span class="file-name">Filename: src/main.rs</span>
|
||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||
</span> let mut s = String::from("hello");
|
||
|
||
let r1 = &mut s;
|
||
let r2 = &mut s;
|
||
|
||
println!("{r1}, {r2}");
|
||
<span class="boring">}</span></code></pre>
|
||
</figure>
|
||
<p>Here’s the error:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling ownership v0.1.0 (file:///projects/ownership)
|
||
error[E0499]: cannot borrow `s` as mutable more than once at a time
|
||
--> src/main.rs:5:14
|
||
|
|
||
4 | let r1 = &mut s;
|
||
| ------ first mutable borrow occurs here
|
||
5 | let r2 = &mut s;
|
||
| ^^^^^^ second mutable borrow occurs here
|
||
6 |
|
||
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
|
||
</code></pre>
|
||
<p>This error says that this code is invalid because we cannot borrow <code>s</code> as
|
||
mutable more than once at a time. The first mutable borrow is in <code>r1</code> and must
|
||
last until it’s used in the <code>println!</code>, but between the creation of that
|
||
mutable reference and its usage, we tried to create another mutable reference
|
||
in <code>r2</code> that borrows the same data as <code>r1</code>.</p>
|
||
<p>The restriction preventing multiple mutable references to the same data at the
|
||
same time allows for mutation but in a very controlled fashion. It’s something
|
||
that new Rustaceans struggle with because most languages let you mutate
|
||
whenever you’d like. The benefit of having this restriction is that Rust can
|
||
prevent data races at compile time. A <em>data race</em> is similar to a race
|
||
condition and happens when these three behaviors occur:</p>
|
||
<ul>
|
||
<li>Two or more pointers access the same data at the same time.</li>
|
||
<li>At least one of the pointers is being used to write to the data.</li>
|
||
<li>There’s no mechanism being used to synchronize access to the data.</li>
|
||
</ul>
|
||
<p>Data races cause undefined behavior and can be difficult to diagnose and fix
|
||
when you’re trying to track them down at runtime; Rust prevents this problem by
|
||
refusing to compile code with data races!</p>
|
||
<p>As always, we can use curly brackets to create a new scope, allowing for
|
||
multiple mutable references, just not <em>simultaneous</em> ones:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span> let mut s = String::from("hello");
|
||
|
||
{
|
||
let r1 = &mut s;
|
||
} // r1 goes out of scope here, so we can make a new reference with no problems.
|
||
|
||
let r2 = &mut s;
|
||
<span class="boring">}</span></code></pre>
|
||
<p>Rust enforces a similar rule for combining mutable and immutable references.
|
||
This code results in an error:</p>
|
||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||
</span> let mut s = String::from("hello");
|
||
|
||
let r1 = &s; // no problem
|
||
let r2 = &s; // no problem
|
||
let r3 = &mut s; // BIG PROBLEM
|
||
|
||
println!("{r1}, {r2}, and {r3}");
|
||
<span class="boring">}</span></code></pre>
|
||
<p>Here’s the error:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling ownership v0.1.0 (file:///projects/ownership)
|
||
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
|
||
--> src/main.rs:6:14
|
||
|
|
||
4 | let r1 = &s; // no problem
|
||
| -- immutable borrow occurs here
|
||
5 | let r2 = &s; // no problem
|
||
6 | let r3 = &mut s; // BIG PROBLEM
|
||
| ^^^^^^ mutable borrow occurs here
|
||
7 |
|
||
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
|
||
</code></pre>
|
||
<p>Whew! We <em>also</em> cannot have a mutable reference while we have an immutable one
|
||
to the same value.</p>
|
||
<p>Users of an immutable reference don’t expect the value to suddenly change out
|
||
from under them! However, multiple immutable references are allowed because no
|
||
one who is just reading the data has the ability to affect anyone else’s
|
||
reading of the data.</p>
|
||
<p>Note that a reference’s scope starts from where it is introduced and continues
|
||
through the last time that reference is used. For instance, this code will
|
||
compile because the last usage of the immutable references is in the <code>println!</code>,
|
||
before the mutable reference is introduced:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span> let mut s = String::from("hello");
|
||
|
||
let r1 = &s; // no problem
|
||
let r2 = &s; // no problem
|
||
println!("{r1} and {r2}");
|
||
// Variables r1 and r2 will not be used after this point.
|
||
|
||
let r3 = &mut s; // no problem
|
||
println!("{r3}");
|
||
<span class="boring">}</span></code></pre>
|
||
<p>The scopes of the immutable references <code>r1</code> and <code>r2</code> end after the <code>println!</code>
|
||
where they are last used, which is before the mutable reference <code>r3</code> is
|
||
created. These scopes don’t overlap, so this code is allowed: The compiler can
|
||
tell that the reference is no longer being used at a point before the end of
|
||
the scope.</p>
|
||
<p>Even though borrowing errors may be frustrating at times, remember that it’s
|
||
the Rust compiler pointing out a potential bug early (at compile time rather
|
||
than at runtime) and showing you exactly where the problem is. Then, you don’t
|
||
have to track down why your data isn’t what you thought it was.</p>
|
||
<h3 id="dangling-references"><a class="header" href="#dangling-references">Dangling References</a></h3>
|
||
<p>In languages with pointers, it’s easy to erroneously create a <em>dangling
|
||
pointer</em>—a pointer that references a location in memory that may have been
|
||
given to someone else—by freeing some memory while preserving a pointer to that
|
||
memory. In Rust, by contrast, the compiler guarantees that references will
|
||
never be dangling references: If you have a reference to some data, the
|
||
compiler will ensure that the data will not go out of scope before the
|
||
reference to the data does.</p>
|
||
<p>Let’s try to create a dangling reference to see how Rust prevents them with a
|
||
compile-time error:</p>
|
||
<figure class="listing">
|
||
<span class="file-name">Filename: src/main.rs</span>
|
||
<pre><code class="language-rust ignore does_not_compile">fn main() {
|
||
let reference_to_nothing = dangle();
|
||
}
|
||
|
||
fn dangle() -> &String {
|
||
let s = String::from("hello");
|
||
|
||
&s
|
||
}</code></pre>
|
||
</figure>
|
||
<p>Here’s the error:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling ownership v0.1.0 (file:///projects/ownership)
|
||
error[E0106]: missing lifetime specifier
|
||
--> src/main.rs:5:16
|
||
|
|
||
5 | fn dangle() -> &String {
|
||
| ^ expected named lifetime parameter
|
||
|
|
||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||
|
|
||
5 | fn dangle() -> &'static String {
|
||
| +++++++
|
||
help: instead, you are more likely to want to return an owned value
|
||
|
|
||
5 - fn dangle() -> &String {
|
||
5 + fn dangle() -> String {
|
||
|
|
||
|
||
For more information about this error, try `rustc --explain E0106`.
|
||
error: could not compile `ownership` (bin "ownership") due to 1 previous error
|
||
</code></pre>
|
||
<p>This error message refers to a feature we haven’t covered yet: lifetimes. We’ll
|
||
discuss lifetimes in detail in Chapter 10. But, if you disregard the parts
|
||
about lifetimes, the message does contain the key to why this code is a problem:</p>
|
||
<pre><code class="language-text">this function's return type contains a borrowed value, but there is no value
|
||
for it to be borrowed from
|
||
</code></pre>
|
||
<p>Let’s take a closer look at exactly what’s happening at each stage of our
|
||
<code>dangle</code> code:</p>
|
||
<figure class="listing">
|
||
<span class="file-name">Filename: src/main.rs</span>
|
||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||
</span><span class="boring"> let reference_to_nothing = dangle();
|
||
</span><span class="boring">}
|
||
</span><span class="boring">
|
||
</span>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.
|
||
// Danger!</code></pre>
|
||
</figure>
|
||
<p>Because <code>s</code> is created inside <code>dangle</code>, when the code of <code>dangle</code> is finished,
|
||
<code>s</code> will be deallocated. But we tried to return a reference to it. That means
|
||
this reference would be pointing to an invalid <code>String</code>. That’s no good! Rust
|
||
won’t let us do this.</p>
|
||
<p>The solution here is to return the <code>String</code> directly:</p>
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span><span class="boring"> let string = no_dangle();
|
||
</span><span class="boring">}
|
||
</span><span class="boring">
|
||
</span>fn no_dangle() -> String {
|
||
let s = String::from("hello");
|
||
|
||
s
|
||
}</code></pre>
|
||
<p>This works without any problems. Ownership is moved out, and nothing is
|
||
deallocated.</p>
|
||
<h3 id="the-rules-of-references"><a class="header" href="#the-rules-of-references">The Rules of References</a></h3>
|
||
<p>Let’s recap what we’ve discussed about references:</p>
|
||
<ul>
|
||
<li>At any given time, you can have <em>either</em> one mutable reference <em>or</em> any
|
||
number of immutable references.</li>
|
||
<li>References must always be valid.</li>
|
||
</ul>
|
||
<p>Next, we’ll look at a different kind of reference: slices.</p>
|
||
</body>
|
||
</html>
|