2022-01-18 22:40:27 +00:00
|
|
|
|
<!-- DO NOT EDIT THIS FILE.
|
|
|
|
|
|
|
|
|
|
This file is periodically generated from the content in the `/src/`
|
|
|
|
|
directory, so all fixes need to be made in `/src/`.
|
|
|
|
|
-->
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
[TOC]
|
|
|
|
|
|
|
|
|
|
# Understanding Ownership
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Ownership is Rust’s most unique feature and has deep implications for the rest
|
2021-11-18 22:28:57 +00:00
|
|
|
|
of the language. It enables Rust to make memory safety guarantees without
|
|
|
|
|
needing a garbage collector, so it’s important to understand how ownership
|
2021-11-18 22:38:12 +00:00
|
|
|
|
works. In this chapter, we’ll talk about ownership as well as several related
|
|
|
|
|
features: borrowing, slices, and how Rust lays data out in memory.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
## What Is Ownership?
|
|
|
|
|
|
2022-08-24 13:12:29 +00:00
|
|
|
|
*Ownership* is a set of rules that govern how a Rust program manages memory.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
All programs have to manage the way they use a computer’s memory while running.
|
2022-08-14 17:47:10 +00:00
|
|
|
|
Some languages have garbage collection that regularly looks for no-longer-used
|
2021-07-26 01:49:50 +00:00
|
|
|
|
memory as the program runs; in other languages, the programmer must explicitly
|
|
|
|
|
allocate and free the memory. Rust uses a third approach: memory is managed
|
2021-11-18 22:38:12 +00:00
|
|
|
|
through a system of ownership with a set of rules that the compiler checks. If
|
2022-05-04 17:01:15 +00:00
|
|
|
|
any of the rules are violated, the program won’t compile. None of the features
|
|
|
|
|
of ownership will slow down your program while it’s running.
|
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
Because ownership is a new concept for many programmers, it does take some time
|
|
|
|
|
to get used to. The good news is that the more experienced you become with Rust
|
2021-11-18 22:38:12 +00:00
|
|
|
|
and the rules of the ownership system, the easier you’ll find it to naturally
|
2021-07-26 01:49:50 +00:00
|
|
|
|
develop code that is safe and efficient. Keep at it!
|
|
|
|
|
|
|
|
|
|
When you understand ownership, you’ll have a solid foundation for understanding
|
|
|
|
|
the features that make Rust unique. In this chapter, you’ll learn ownership by
|
|
|
|
|
working through some examples that focus on a very common data structure:
|
|
|
|
|
strings.
|
|
|
|
|
|
|
|
|
|
> ### The Stack and the Heap
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-11-18 22:38:12 +00:00
|
|
|
|
> Many programming languages don’t require you to think about the stack and the
|
2022-08-15 01:23:58 +00:00
|
|
|
|
heap very often. But in a systems programming language like Rust, whether a
|
|
|
|
|
value is on the stack or the heap affects how the language behaves and why you
|
|
|
|
|
have to make certain decisions. Parts of ownership will be described in
|
|
|
|
|
relation to the stack and the heap later in this chapter, so here is a brief
|
|
|
|
|
explanation in preparation.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-11-18 22:38:12 +00:00
|
|
|
|
> Both the stack and the heap are parts of memory available to your code to use
|
2022-08-15 01:23:58 +00:00
|
|
|
|
at runtime, but they are structured in different ways. The stack stores values
|
|
|
|
|
in the order it gets them and removes the values in the opposite order. This is
|
|
|
|
|
referred to as *last in, first out*. Think of a stack of plates: when you add
|
|
|
|
|
more plates, you put them on top of the pile, and when you need a plate, you
|
|
|
|
|
take one off the top. Adding or removing plates from the middle or bottom
|
2022-09-09 23:49:52 +00:00
|
|
|
|
wouldn’t work as well! Adding data is called *pushing onto the stack*, and
|
2022-08-15 01:23:58 +00:00
|
|
|
|
removing data is called *popping off the stack*. All data stored on the stack
|
|
|
|
|
must have a known, fixed size. Data with an unknown size at compile time or a
|
|
|
|
|
size that might change must be stored on the heap instead.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-11-18 22:38:12 +00:00
|
|
|
|
> The heap is less organized: when you put data on the heap, you request a
|
2022-08-15 01:23:58 +00:00
|
|
|
|
certain amount of space. The memory allocator finds an empty spot in the heap
|
|
|
|
|
that is big enough, marks it as being in use, and returns a *pointer*, which is
|
2022-09-09 23:49:52 +00:00
|
|
|
|
the address of that location. This process is called *allocating on the heap*
|
2022-08-15 01:23:58 +00:00
|
|
|
|
and is sometimes abbreviated as just *allocating* (pushing values onto the
|
|
|
|
|
stack is not considered allocating). Because the pointer to the heap is a
|
|
|
|
|
known, fixed size, you can store the pointer on the stack, but when you want
|
|
|
|
|
the actual data, you must follow the pointer. Think of being seated at a
|
|
|
|
|
restaurant. When you enter, you state the number of people in your group, and
|
|
|
|
|
the host finds an empty table that fits everyone and leads you there. If
|
|
|
|
|
someone in your group comes late, they can ask where you’ve been seated to find
|
|
|
|
|
you.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-07-26 01:49:50 +00:00
|
|
|
|
> Pushing to the stack is faster than allocating on the heap because the
|
2022-08-15 01:23:58 +00:00
|
|
|
|
allocator never has to search for a place to store new data; that location is
|
|
|
|
|
always at the top of the stack. Comparatively, allocating space on the heap
|
|
|
|
|
requires more work because the allocator must first find a big enough space to
|
|
|
|
|
hold the data and then perform bookkeeping to prepare for the next allocation.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-07-26 01:49:50 +00:00
|
|
|
|
> Accessing data in the heap is slower than accessing data on the stack because
|
2022-08-15 01:23:58 +00:00
|
|
|
|
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).
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-07-26 01:49:50 +00:00
|
|
|
|
> When your code calls a function, the values passed into the function
|
2022-08-15 01:23:58 +00:00
|
|
|
|
(including, potentially, pointers to data on the heap) and the function’s local
|
|
|
|
|
variables get pushed onto the stack. When the function is over, those values
|
|
|
|
|
get popped off the stack.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
>
|
2021-07-26 01:49:50 +00:00
|
|
|
|
> Keeping track of what parts of code are using what data on the heap,
|
2022-08-15 01:23:58 +00:00
|
|
|
|
minimizing the amount of duplicate data on the heap, and cleaning up unused
|
|
|
|
|
data on the heap so you don’t run out of space are all problems that ownership
|
|
|
|
|
addresses. Once you understand ownership, you won’t need to think about the
|
|
|
|
|
stack and the heap very often, but knowing that the main purpose of ownership
|
|
|
|
|
is to manage heap data can help explain why it works the way it does.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
### Ownership Rules
|
|
|
|
|
|
|
|
|
|
First, let’s take a look at the ownership rules. Keep these rules in mind as we
|
|
|
|
|
work through the examples that illustrate them:
|
|
|
|
|
|
2022-05-04 17:01:15 +00:00
|
|
|
|
* Each value in Rust has an *owner*.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
* There can only be one owner at a time.
|
|
|
|
|
* When the owner goes out of scope, the value will be dropped.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
### Variable Scope
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Now that we’re past basic Rust syntax, we won’t include all the `fn main() {`
|
|
|
|
|
code in examples, so if you’re following along, make sure to put the following
|
2021-07-26 01:49:50 +00:00
|
|
|
|
examples inside a `main` function manually. As a result, our examples will be a
|
|
|
|
|
bit more concise, letting us focus on the actual details rather than
|
|
|
|
|
boilerplate code.
|
|
|
|
|
|
|
|
|
|
As a first example of ownership, we’ll look at the *scope* of some variables. A
|
2021-11-18 22:38:12 +00:00
|
|
|
|
scope is the range within a program for which an item is valid. Take the
|
|
|
|
|
following variable:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let s = "hello";
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The variable `s` refers to a string literal, where the value of the string is
|
|
|
|
|
hardcoded into the text of our program. The variable is valid from the point at
|
2021-11-18 22:38:12 +00:00
|
|
|
|
which it’s declared until the end of the current *scope*. Listing 4-1 shows a
|
|
|
|
|
program with comments annotating where the variable `s` would be valid.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
2022-08-14 17:47:10 +00:00
|
|
|
|
{ // s is not valid here, since it's not yet declared
|
|
|
|
|
let s = "hello"; // s is valid from this point forward
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
// do stuff with s
|
|
|
|
|
} // this scope is now over, and s is no longer valid
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-1: A variable and the scope in which it is valid
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
In other words, there are two important points in time here:
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
* When `s` comes *into* scope, it is valid.
|
|
|
|
|
* It remains valid until it goes *out of* scope.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
At this point, the relationship between scopes and when variables are valid is
|
|
|
|
|
similar to that in other programming languages. Now we’ll build on top of this
|
|
|
|
|
understanding by introducing the `String` type.
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
### The String Type
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
To illustrate the rules of ownership, we need a data type that is more complex
|
2022-08-14 17:47:10 +00:00
|
|
|
|
than those we covered in “Data Types” on page XX. The types covered previously
|
|
|
|
|
are of a known size, can be stored on the stack and popped off the stack when
|
|
|
|
|
their scope is over, and can be quickly and trivially copied to make a new,
|
|
|
|
|
independent instance if another part of code needs to use the same value in a
|
|
|
|
|
different scope. But we want to look at data that is stored on the heap and
|
|
|
|
|
explore how Rust knows when to clean up that data, and the `String` type is a
|
|
|
|
|
great example.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
We’ll concentrate on the parts of `String` that relate to ownership. These
|
|
|
|
|
aspects also apply to other complex data types, whether they are provided by
|
|
|
|
|
the standard library or created by you. We’ll discuss `String` in more depth in
|
|
|
|
|
Chapter 8.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
We’ve already seen string literals, where a string value is hardcoded into our
|
|
|
|
|
program. String literals are convenient, but they aren’t suitable for every
|
|
|
|
|
situation in which we may want to use text. One reason is that they’re
|
|
|
|
|
immutable. Another is that not every string value can be known when we write
|
|
|
|
|
our code: for example, what if we want to take user input and store it? For
|
|
|
|
|
these situations, Rust has a second string type, `String`. This type manages
|
|
|
|
|
data allocated on the heap and as such is able to store an amount of text that
|
|
|
|
|
is unknown to us at compile time. You can create a `String` from a string
|
|
|
|
|
literal using the `from` function, like so:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let s = String::from("hello");
|
|
|
|
|
```
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
The double colon `::` operator allows us to namespace this particular `from`
|
|
|
|
|
function under the `String` type rather than using some sort of name like
|
2022-08-24 13:12:29 +00:00
|
|
|
|
`string_from`. We’ll discuss this syntax more in “Method Syntax” on page XX,
|
|
|
|
|
and when we talk about namespacing with modules in “Paths for Referring to an
|
|
|
|
|
Item in the Module Tree” on page XX.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
This kind of string *can* be mutated:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let mut s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
s.push_str(", world!"); // push_str() appends a literal to a String
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{s}"); // This will print `hello, world!`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
So, what’s the difference here? Why can `String` be mutated but literals
|
2022-08-14 17:47:10 +00:00
|
|
|
|
cannot? The difference is in how these two types deal with memory.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
### Memory and Allocation
|
|
|
|
|
|
|
|
|
|
In the case of a string literal, we know the contents at compile time, so the
|
|
|
|
|
text is hardcoded directly into the final executable. This is why string
|
|
|
|
|
literals are fast and efficient. But these properties only come from the string
|
|
|
|
|
literal’s immutability. Unfortunately, we can’t put a blob of memory into the
|
|
|
|
|
binary for each piece of text whose size is unknown at compile time and whose
|
|
|
|
|
size might change while running the program.
|
|
|
|
|
|
|
|
|
|
With the `String` type, in order to support a mutable, growable piece of text,
|
|
|
|
|
we need to allocate an amount of memory on the heap, unknown at compile time,
|
|
|
|
|
to hold the contents. This means:
|
|
|
|
|
|
|
|
|
|
* The memory must be requested from the memory allocator at runtime.
|
2022-08-14 17:47:10 +00:00
|
|
|
|
* We need a way of returning this memory to the allocator when we’re done with
|
|
|
|
|
our `String`.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
That first part is done by us: when we call `String::from`, its implementation
|
|
|
|
|
requests the memory it needs. This is pretty much universal in programming
|
|
|
|
|
languages.
|
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
However, the second part is different. In languages with a *garbage collector
|
|
|
|
|
(GC)*, the GC keeps track of and cleans up memory that isn’t being used
|
2021-11-18 22:38:12 +00:00
|
|
|
|
anymore, and we don’t need to think about it. In most languages without a GC,
|
2022-08-14 17:47:10 +00:00
|
|
|
|
it’s our responsibility to identify when memory is no longer being used and to
|
2022-05-04 17:01:15 +00:00
|
|
|
|
call code to explicitly free it, just as we did to request it. Doing this
|
2021-11-18 22:38:12 +00:00
|
|
|
|
correctly has historically been a difficult programming problem. If we forget,
|
|
|
|
|
we’ll waste memory. If we do it too early, we’ll have an invalid variable. If
|
|
|
|
|
we do it twice, that’s a bug too. We need to pair exactly one `allocate` with
|
|
|
|
|
exactly one `free`.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Rust takes a different path: the memory is automatically returned once the
|
|
|
|
|
variable that owns it goes out of scope. Here’s a version of our scope example
|
|
|
|
|
from Listing 4-1 using a `String` instead of a string literal:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
{
|
|
|
|
|
let s = String::from("hello"); // s is valid from this point forward
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
// do stuff with s
|
|
|
|
|
} // this scope is now over, and s is no
|
|
|
|
|
// longer valid
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
There is a natural point at which we can return the memory our `String` needs
|
|
|
|
|
to the allocator: when `s` goes out of scope. When a variable goes out of
|
|
|
|
|
scope, Rust calls a special function for us. This function is called `drop`,
|
|
|
|
|
and it’s where the author of `String` can put the code to return the memory.
|
|
|
|
|
Rust calls `drop` automatically at the closing curly bracket.
|
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
> Note: In C++, this pattern of deallocating resources at the end of an item’s
|
2022-08-14 17:47:10 +00:00
|
|
|
|
lifetime is sometimes called *Resource Acquisition Is Initialization* *(RAII)*.
|
|
|
|
|
The `drop` function in Rust will be familiar to you if you’ve used RAII
|
|
|
|
|
patterns.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
This pattern has a profound impact on the way Rust code is written. It may seem
|
|
|
|
|
simple right now, but the behavior of code can be unexpected in more
|
|
|
|
|
complicated situations when we want to have multiple variables use the data
|
|
|
|
|
we’ve allocated on the heap. Let’s explore some of those situations now.
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
#### Variables and Data Interacting with Move
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Multiple variables can interact with the same data in different ways in Rust.
|
|
|
|
|
Let’s look at an example using an integer in Listing 4-2.
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-24 00:15:07 +00:00
|
|
|
|
let x = 5;
|
|
|
|
|
let y = x;
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-2: Assigning the integer value of variable `x` to `y`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
We can probably guess what this is doing: “bind the value `5` to `x`; then make
|
|
|
|
|
a copy of the value in `x` and bind it to `y`.” We now have two variables, `x`
|
|
|
|
|
and `y`, and both equal `5`. This is indeed what is happening, because integers
|
|
|
|
|
are simple values with a known, fixed size, and these two `5` values are pushed
|
|
|
|
|
onto the stack.
|
|
|
|
|
|
|
|
|
|
Now let’s look at the `String` version:
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-24 00:15:07 +00:00
|
|
|
|
let s1 = String::from("hello");
|
|
|
|
|
let s2 = s1;
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
This looks very similar, so we might assume that the way it works would be the
|
|
|
|
|
same: that is, the second line would make a copy of the value in `s1` and bind
|
|
|
|
|
it to `s2`. But this isn’t quite what happens.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Take a look at Figure 4-1 to see what is happening to `String` under the
|
|
|
|
|
covers. A `String` is made up of three parts, shown on the left: a pointer to
|
|
|
|
|
the memory that holds the contents of the string, a length, and a capacity.
|
|
|
|
|
This group of data is stored on the stack. On the right is the memory on the
|
|
|
|
|
heap that holds the contents.
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Figure 4-1: Representation in memory of a `String` holding the value `"hello"`
|
|
|
|
|
bound to `s1`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:57:06 +00:00
|
|
|
|
The length is how much memory, in bytes, the contents of the `String` are
|
2021-07-26 01:49:50 +00:00
|
|
|
|
currently using. The capacity is the total amount of memory, in bytes, that the
|
2022-08-14 17:47:10 +00:00
|
|
|
|
`String` has received from the allocator. The difference between length and
|
|
|
|
|
capacity matters, but not in this context, so for now, it’s fine to ignore the
|
|
|
|
|
capacity.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
When we assign `s1` to `s2`, the `String` data is copied, meaning we copy the
|
|
|
|
|
pointer, the length, and the capacity that are on the stack. We do not copy the
|
|
|
|
|
data on the heap that the pointer refers to. In other words, the data
|
|
|
|
|
representation in memory looks like Figure 4-2.
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Figure 4-2: Representation in memory of the variable `s2` that has a copy of
|
|
|
|
|
the pointer, length, and capacity of `s1`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:57:06 +00:00
|
|
|
|
The representation does *not* look like Figure 4-3, which is what memory would
|
|
|
|
|
look like if Rust instead copied the heap data as well. If Rust did this, the
|
|
|
|
|
operation `s2 = s1` could be very expensive in terms of runtime performance if
|
|
|
|
|
the data on the heap were large.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Figure 4-3: Another possibility for what `s2 = s1` might do if Rust copied the
|
|
|
|
|
heap data as well
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:57:06 +00:00
|
|
|
|
Earlier, we said that when a variable goes out of scope, Rust automatically
|
|
|
|
|
calls the `drop` function and cleans up the heap memory for that variable. But
|
|
|
|
|
Figure 4-2 shows both data pointers pointing to the same location. This is a
|
|
|
|
|
problem: when `s2` and `s1` go out of scope, they will both try to free the
|
|
|
|
|
same memory. This is known as a *double free* error and is one of the memory
|
|
|
|
|
safety bugs we mentioned previously. Freeing memory twice can lead to memory
|
|
|
|
|
corruption, which can potentially lead to security vulnerabilities.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
To ensure memory safety, after the line `let s2 = s1;`, Rust considers `s1` as
|
|
|
|
|
no longer valid. Therefore, Rust doesn’t need to free anything when `s1` goes
|
|
|
|
|
out of scope. Check out what happens when you try to use `s1` after `s2` is
|
|
|
|
|
created; it won’t work:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let s1 = String::from("hello");
|
|
|
|
|
let s2 = s1;
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{s1}, world!");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
You’ll get an error like this because Rust prevents you from using the
|
|
|
|
|
invalidated reference:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
error[E0382]: borrow of moved value: `s1`
|
|
|
|
|
--> src/main.rs:5:28
|
|
|
|
|
|
|
|
|
|
|
2 | let s1 = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
| -- move occurs because `s1` has type `String`, which
|
2022-08-24 13:12:29 +00:00
|
|
|
|
does not implement the `Copy` trait
|
2021-07-26 01:49:50 +00:00
|
|
|
|
3 | let s2 = s1;
|
|
|
|
|
| -- value moved here
|
|
|
|
|
4 |
|
2022-08-15 01:23:58 +00:00
|
|
|
|
5 | println!("{s1}, world!");
|
|
|
|
|
| ^^ value borrowed here after move
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you’ve heard the terms *shallow copy* and *deep copy* while working with
|
|
|
|
|
other languages, the concept of copying the pointer, length, and capacity
|
|
|
|
|
without copying the data probably sounds like making a shallow copy. But
|
2022-08-14 17:47:10 +00:00
|
|
|
|
because Rust also invalidates the first variable, instead of being called a
|
|
|
|
|
shallow copy, it’s known as a *move*. In this example, we would say that `s1`
|
|
|
|
|
was *moved* into `s2`. So, what actually happens is shown in Figure 4-4.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Figure 4-4: Representation in memory after `s1` has been invalidated
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:57:06 +00:00
|
|
|
|
That solves our problem! With only `s2` valid, when it goes out of scope it
|
|
|
|
|
alone will free the memory, and we’re done.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
In addition, there’s a design choice that’s implied by this: Rust will never
|
|
|
|
|
automatically create “deep” copies of your data. Therefore, any *automatic*
|
|
|
|
|
copying can be assumed to be inexpensive in terms of runtime performance.
|
|
|
|
|
|
2022-08-24 13:12:29 +00:00
|
|
|
|
#### Variables and Data Interacting with Clone
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
If we *do* want to deeply copy the heap data of the `String`, not just the
|
|
|
|
|
stack data, we can use a common method called `clone`. We’ll discuss method
|
|
|
|
|
syntax in Chapter 5, but because methods are a common feature in many
|
|
|
|
|
programming languages, you’ve probably seen them before.
|
|
|
|
|
|
|
|
|
|
Here’s an example of the `clone` method in action:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let s1 = String::from("hello");
|
|
|
|
|
let s2 = s1.clone();
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("s1 = {s1}, s2 = {s2}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This works just fine and explicitly produces the behavior shown in Figure 4-3,
|
|
|
|
|
where the heap data *does* get copied.
|
|
|
|
|
|
|
|
|
|
When you see a call to `clone`, you know that some arbitrary code is being
|
|
|
|
|
executed and that code may be expensive. It’s a visual indicator that something
|
|
|
|
|
different is going on.
|
|
|
|
|
|
|
|
|
|
#### Stack-Only Data: Copy
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
There’s another wrinkle we haven’t talked about yet. This code using
|
|
|
|
|
integers—part of which was shown in Listing 4-2—works and is valid:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let x = 5;
|
|
|
|
|
let y = x;
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("x = {x}, y = {y}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
But this code seems to contradict what we just learned: we don’t have a call to
|
|
|
|
|
`clone`, but `x` is still valid and wasn’t moved into `y`.
|
|
|
|
|
|
|
|
|
|
The reason is that types such as integers that have a known size at compile
|
|
|
|
|
time are stored entirely on the stack, so copies of the actual values are quick
|
|
|
|
|
to make. That means there’s no reason we would want to prevent `x` from being
|
|
|
|
|
valid after we create the variable `y`. In other words, there’s no difference
|
|
|
|
|
between deep and shallow copying here, so calling `clone` wouldn’t do anything
|
2022-08-14 17:47:10 +00:00
|
|
|
|
different from the usual shallow copying, and we can leave it out.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Rust has a special annotation called the `Copy` trait that we can place on
|
2022-05-04 17:01:15 +00:00
|
|
|
|
types that are stored on the stack, as integers are (we’ll talk more about
|
|
|
|
|
traits in Chapter 10). If a type implements the `Copy` trait, variables that
|
|
|
|
|
use it do not move, but rather are trivially copied, making them still valid
|
|
|
|
|
after assignment to another variable.
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Rust won’t let us annotate a type with `Copy` if the type, or any of its parts,
|
|
|
|
|
has implemented the `Drop` trait. If the type needs something special to happen
|
|
|
|
|
when the value goes out of scope and we add the `Copy` annotation to that type,
|
|
|
|
|
we’ll get a compile-time error. To learn about how to add the `Copy` annotation
|
2022-08-14 17:47:10 +00:00
|
|
|
|
to your type to implement the trait, see “Derivable Traits” on page XX.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
So, what types implement the `Copy` trait? You can check the documentation for
|
2021-07-26 01:49:50 +00:00
|
|
|
|
the given type to be sure, but as a general rule, any group of simple scalar
|
|
|
|
|
values can implement `Copy`, and nothing that requires allocation or is some
|
|
|
|
|
form of resource can implement `Copy`. Here are some of the types that
|
|
|
|
|
implement `Copy`:
|
|
|
|
|
|
|
|
|
|
* All the integer types, such as `u32`.
|
|
|
|
|
* The Boolean type, `bool`, with values `true` and `false`.
|
2022-08-14 17:47:10 +00:00
|
|
|
|
* All the floating-point types, such as `f64`.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
* The character type, `char`.
|
|
|
|
|
* Tuples, if they only contain types that also implement `Copy`. For example,
|
2022-08-14 17:47:10 +00:00
|
|
|
|
`(i32, i32)` implements `Copy`, but `(i32, String)` does not.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
### Ownership and Functions
|
|
|
|
|
|
2022-02-04 22:27:40 +00:00
|
|
|
|
The mechanics of passing a value to a function are similar to those when
|
2021-07-26 01:49:50 +00:00
|
|
|
|
assigning a value to a variable. Passing a variable to a function will move or
|
|
|
|
|
copy, just as assignment does. Listing 4-3 has an example with some annotations
|
|
|
|
|
showing where variables go into and out of scope.
|
|
|
|
|
|
2022-08-24 13:12:29 +00:00
|
|
|
|
```
|
|
|
|
|
// src/main.rs
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn main() {
|
|
|
|
|
let s = String::from("hello"); // s comes into scope
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
takes_ownership(s); // s's value moves into the function...
|
|
|
|
|
// ... and so is no longer valid here
|
|
|
|
|
|
|
|
|
|
let x = 5; // x comes into scope
|
|
|
|
|
|
|
|
|
|
makes_copy(x); // x would move into the function,
|
|
|
|
|
// but i32 is Copy, so it's okay to still
|
|
|
|
|
// use x afterward
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
|
|
|
|
} // Here, x goes out of scope, then s. However, because s's value was moved,
|
2022-08-15 01:23:58 +00:00
|
|
|
|
// nothing special happens
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn takes_ownership(some_string: String) { // some_string comes into scope
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{some_string}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
} // Here, some_string goes out of scope and `drop` is called. The backing
|
2022-08-14 17:47:10 +00:00
|
|
|
|
// memory is freed
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
fn makes_copy(some_integer: i32) { // some_integer comes into scope
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{some_integer}");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
} // Here, some_integer goes out of scope. Nothing special happens
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-3: Functions with ownership and scope annotated
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
If we tried to use `s` after the call to `takes_ownership`, Rust would throw a
|
|
|
|
|
compile-time error. These static checks protect us from mistakes. Try adding
|
|
|
|
|
code to `main` that uses `s` and `x` to see where you can use them and where
|
|
|
|
|
the ownership rules prevent you from doing so.
|
|
|
|
|
|
|
|
|
|
### Return Values and Scope
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
Returning values can also transfer ownership. Listing 4-4 shows an example of a
|
|
|
|
|
function that returns some value, with similar annotations as those in Listing
|
|
|
|
|
4-3.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-24 13:12:29 +00:00
|
|
|
|
```
|
|
|
|
|
// src/main.rs
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn main() {
|
|
|
|
|
let s1 = gives_ownership(); // gives_ownership moves its return
|
|
|
|
|
// value into s1
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let s2 = String::from("hello"); // s2 comes into scope
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let s3 = takes_and_gives_back(s2); // s2 is moved into
|
|
|
|
|
// takes_and_gives_back, which also
|
|
|
|
|
// moves its return value into s3
|
|
|
|
|
} // Here, s3 goes out of scope and is dropped. s2 was moved, so nothing
|
2022-08-14 17:47:10 +00:00
|
|
|
|
// happens. s1 goes out of scope and is dropped
|
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn gives_ownership() -> String { // gives_ownership will move its
|
|
|
|
|
// return value into the function
|
|
|
|
|
// that calls it
|
|
|
|
|
|
|
|
|
|
let some_string = String::from("yours"); // some_string comes into scope
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
some_string // some_string is returned and
|
|
|
|
|
// moves out to the calling
|
|
|
|
|
// function
|
|
|
|
|
}
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
|
|
|
|
// This function takes a String and returns a String
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
|
|
|
|
|
// scope
|
|
|
|
|
|
|
|
|
|
a_string // a_string is returned and moves out to the calling function
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-4: Transferring ownership of return values
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
The ownership of a variable follows the same pattern every time: assigning a
|
|
|
|
|
value to another variable moves it. When a variable that includes data on the
|
2021-11-18 22:38:12 +00:00
|
|
|
|
heap goes out of scope, the value will be cleaned up by `drop` unless ownership
|
|
|
|
|
of the data has been moved to another variable.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
While this works, taking ownership and then returning ownership with every
|
|
|
|
|
function is a bit tedious. What if we want to let a function use a value but
|
|
|
|
|
not take ownership? It’s quite annoying that anything we pass in also needs to
|
|
|
|
|
be passed back if we want to use it again, in addition to any data resulting
|
|
|
|
|
from the body of the function that we might want to return as well.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Rust does let us return multiple values using a tuple, as shown in Listing 4-5.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let s1 = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let (s2, len) = calculate_length(s1);
|
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("The length of '{s2}' is {len}.");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn calculate_length(s: String) -> (String, usize) {
|
|
|
|
|
let length = s.len(); // len() returns the length of a String
|
|
|
|
|
|
|
|
|
|
(s, length)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-5: Returning ownership of parameters
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
But this is too much ceremony and a lot of work for a concept that should be
|
2021-11-18 22:38:12 +00:00
|
|
|
|
common. Luckily for us, Rust has a feature for using a value without
|
|
|
|
|
transferring ownership, called *references*.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
## References and Borrowing
|
|
|
|
|
|
|
|
|
|
The issue with the tuple code in Listing 4-5 is that we have to return the
|
|
|
|
|
`String` to the calling function so we can still use the `String` after the
|
|
|
|
|
call to `calculate_length`, because the `String` was moved into
|
2021-11-18 22:38:12 +00:00
|
|
|
|
`calculate_length`. Instead, we can provide a reference to the `String` value.
|
|
|
|
|
A *reference* is like a pointer in that it’s an address we can follow to access
|
2022-05-04 17:01:15 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
Here is how you would define and use a `calculate_length` function that has a
|
2021-11-18 22:38:12 +00:00
|
|
|
|
reference to an object as a parameter instead of taking ownership of the value:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let s1 = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let len = calculate_length(&s1);
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("The length of '{s1}' is {len}.");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
}
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn calculate_length(s: &String) -> usize {
|
|
|
|
|
s.len()
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
First, notice that all the tuple code in the variable declaration and the
|
|
|
|
|
function return value is gone. Second, note that we pass `&s1` into
|
|
|
|
|
`calculate_length` and, in its definition, we take `&String` rather than
|
2021-11-18 22:38:12 +00:00
|
|
|
|
`String`. These ampersands represent *references*, and they allow you to refer
|
|
|
|
|
to some value without taking ownership of it. Figure 4-5 depicts this concept.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Figure 4-5: A diagram of `&String s` pointing at `String s1`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:57:06 +00:00
|
|
|
|
> Note: The opposite of referencing by using `&` is *dereferencing*, which is
|
|
|
|
|
accomplished with the dereference operator, `*`. We’ll see some uses of the
|
|
|
|
|
dereference operator in Chapter 8 and discuss details of dereferencing in
|
|
|
|
|
Chapter 15.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Let’s take a closer look at the function call here:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let s1 = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let len = calculate_length(&s1);
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `&s1` syntax lets us create a reference that *refers* to the value of `s1`
|
|
|
|
|
but does not own it. Because it does not own it, the value it points to will
|
|
|
|
|
not be dropped when the reference stops being used.
|
|
|
|
|
|
|
|
|
|
Likewise, the signature of the function uses `&` to indicate that the type of
|
|
|
|
|
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 it does not have ownership of what
|
2022-08-15 01:23:58 +00:00
|
|
|
|
// it refers to, the String is not dropped
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The scope in which the variable `s` is valid is the same as any function
|
2021-11-18 22:38:12 +00:00
|
|
|
|
parameter’s scope, but the value pointed to by the reference is not dropped
|
2022-08-14 17:47:10 +00:00
|
|
|
|
when `s` stops being used, because `s` doesn’t have ownership. When functions
|
2021-11-18 22:38:12 +00:00
|
|
|
|
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.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
We call the action of creating a reference *borrowing*. As in real life, if a
|
|
|
|
|
person owns something, you can borrow it from them. When you’re done, you have
|
2021-11-18 22:38:12 +00:00
|
|
|
|
to give it back. You don’t own it.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
So, what happens if we try to modify something we’re borrowing? Try the code in
|
2021-07-26 01:49:50 +00:00
|
|
|
|
Listing 4-6. Spoiler alert: it doesn’t work!
|
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
change(&s);
|
|
|
|
|
}
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn change(some_string: &String) {
|
|
|
|
|
some_string.push_str(", world");
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-6: Attempting to modify a borrowed value
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Here’s the error:
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-14 17:47:10 +00:00
|
|
|
|
error[E0596]: cannot borrow `*some_string` as mutable, as it is behind a `&`
|
|
|
|
|
reference
|
2021-07-26 01:49:50 +00:00
|
|
|
|
--> src/main.rs:8:5
|
|
|
|
|
|
|
|
|
|
|
7 | fn change(some_string: &String) {
|
2022-08-14 17:47:10 +00:00
|
|
|
|
| ------- help: consider changing this to be a mutable
|
|
|
|
|
reference: `&mut String`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
8 | some_string.push_str(", world");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `some_string` is a `&` reference, so
|
|
|
|
|
the data it refers to cannot be borrowed as mutable
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Just as variables are immutable by default, so are references. We’re not
|
|
|
|
|
allowed to modify something we have a reference to.
|
|
|
|
|
|
|
|
|
|
### Mutable References
|
|
|
|
|
|
2021-11-18 22:28:57 +00:00
|
|
|
|
We can fix the code from Listing 4-6 to allow us to modify a borrowed value
|
2021-11-18 22:38:12 +00:00
|
|
|
|
with just a few small tweaks that use, instead, a *mutable reference*:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let mut s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
change(&mut s);
|
|
|
|
|
}
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn change(some_string: &mut String) {
|
|
|
|
|
some_string.push_str(", world");
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
First we change `s` to be `mut`. Then we create a mutable reference with `&mut
|
2021-11-18 22:38:12 +00:00
|
|
|
|
s` where we call the `change` function, and update the function signature to
|
|
|
|
|
accept a mutable reference with `some_string: &mut String`. This makes it very
|
|
|
|
|
clear that the `change` function will mutate the value it borrows.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-05-04 17:01:15 +00:00
|
|
|
|
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 `s` will fail:
|
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-24 00:15:07 +00:00
|
|
|
|
let mut s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2022-08-24 00:15:07 +00:00
|
|
|
|
let r1 = &mut s;
|
|
|
|
|
let r2 = &mut s;
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-24 00:15:07 +00:00
|
|
|
|
println!("{r1}, {r2}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Here’s the error:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
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 |
|
2022-08-15 01:23:58 +00:00
|
|
|
|
7 | println!("{r1}, {r2}");
|
|
|
|
|
| -- first borrow later used here
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This error says that this code is invalid because we cannot borrow `s` as
|
|
|
|
|
mutable more than once at a time. The first mutable borrow is in `r1` and must
|
|
|
|
|
last until it’s used in the `println!`, but between the creation of that
|
|
|
|
|
mutable reference and its usage, we tried to create another mutable reference
|
|
|
|
|
in `r2` that borrows the same data as `r1`.
|
|
|
|
|
|
|
|
|
|
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
|
2022-08-14 17:47:10 +00:00
|
|
|
|
that new Rustaceans struggle with because most languages let you mutate
|
2021-11-18 22:38:12 +00:00
|
|
|
|
whenever you’d like. The benefit of having this restriction is that Rust can
|
|
|
|
|
prevent data races at compile time. A *data race* is similar to a race
|
|
|
|
|
condition and happens when these three behaviors occur:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
* Two or more pointers access the same data at the same time.
|
|
|
|
|
* At least one of the pointers is being used to write to the data.
|
|
|
|
|
* There’s no mechanism being used to synchronize access to the data.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
Data races cause undefined behavior and can be difficult to diagnose and fix
|
2022-08-14 17:47:10 +00:00
|
|
|
|
when you’re trying to track them down at runtime; Rust prevents this problem by
|
|
|
|
|
refusing to compile code with data races!
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
As always, we can use curly brackets to create a new scope, allowing for
|
|
|
|
|
multiple mutable references, just not *simultaneous* ones:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let mut s = String::from("hello");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
{
|
|
|
|
|
let r1 = &mut s;
|
2022-08-14 17:47:10 +00:00
|
|
|
|
} // r1 goes out of scope here, so we can make a new reference with no problems
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let r2 = &mut s;
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Rust enforces a similar rule for combining mutable and immutable references.
|
|
|
|
|
This code results in an error:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let mut s = String::from("hello");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let r1 = &s; // no problem
|
|
|
|
|
let r2 = &s; // no problem
|
|
|
|
|
let r3 = &mut s; // BIG PROBLEM
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{r1}, {r2}, and {r3}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Here’s the error:
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-14 17:47:10 +00:00
|
|
|
|
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as
|
|
|
|
|
immutable
|
2021-07-26 01:49:50 +00:00
|
|
|
|
--> 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 |
|
2022-08-15 01:23:58 +00:00
|
|
|
|
8 | println!("{r1}, {r2}, and {r3}");
|
|
|
|
|
| -- immutable borrow later used here
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Whew! We *also* cannot have a mutable reference while we have an immutable one
|
|
|
|
|
to the same value.
|
2022-05-04 17:01:15 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
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.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
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, the `println!`,
|
|
|
|
|
occurs before the mutable reference is introduced:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let mut s = String::from("hello");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let r1 = &s; // no problem
|
|
|
|
|
let r2 = &s; // no problem
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{r1} and {r2}");
|
2021-11-18 22:38:12 +00:00
|
|
|
|
// variables r1 and r2 will not be used after this point
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
let r3 = &mut s; // no problem
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("{r3}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The scopes of the immutable references `r1` and `r2` end after the `println!`
|
|
|
|
|
where they are last used, which is before the mutable reference `r3` is
|
2022-08-15 01:23:58 +00:00
|
|
|
|
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.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
### Dangling References
|
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
In languages with pointers, it’s easy to erroneously create a *dangling
|
|
|
|
|
pointer*—a pointer that references a location in memory that may have been
|
2022-08-14 17:47:10 +00:00
|
|
|
|
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
|
2021-07-26 01:49:50 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Let’s try to create a dangling reference to see how Rust prevents them with a
|
2021-07-26 01:49:50 +00:00
|
|
|
|
compile-time error:
|
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let reference_to_nothing = dangle();
|
|
|
|
|
}
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn dangle() -> &String {
|
|
|
|
|
let s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
&s
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Here’s the error:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
error[E0106]: missing lifetime specifier
|
|
|
|
|
--> src/main.rs:5:16
|
|
|
|
|
|
|
|
|
|
|
5 | fn dangle() -> &String {
|
|
|
|
|
| ^ expected named lifetime parameter
|
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
= help: this function's return type contains a borrowed value,
|
|
|
|
|
but there is no value for it to be borrowed from
|
2021-07-26 01:49:50 +00:00
|
|
|
|
help: consider using the `'static` lifetime
|
|
|
|
|
|
|
|
|
|
|
5 | fn dangle() -> &'static String {
|
2022-05-04 17:03:18 +00:00
|
|
|
|
| ~~~~~~~~
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-15 01:23:58 +00:00
|
|
|
|
this function's return type contains a borrowed value, but there
|
|
|
|
|
is no value for it to be borrowed from
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Let’s take a closer look at exactly what’s happening at each stage of our
|
|
|
|
|
`dangle` code:
|
|
|
|
|
|
2022-08-24 13:12:29 +00:00
|
|
|
|
```
|
|
|
|
|
// src/main.rs
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn dangle() -> &String { // dangle returns a reference to a String
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let s = String::from("hello"); // s is a new String
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
&s // we return a reference to the String, s
|
2022-08-14 17:47:10 +00:00
|
|
|
|
} // Here, s goes out of scope and is dropped, so its memory goes away
|
2021-07-26 01:49:50 +00:00
|
|
|
|
// Danger!
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Because `s` is created inside `dangle`, when the code of `dangle` is finished,
|
|
|
|
|
`s` will be deallocated. But we tried to return a reference to it. That means
|
|
|
|
|
this reference would be pointing to an invalid `String`. That’s no good! Rust
|
|
|
|
|
won’t let us do this.
|
|
|
|
|
|
|
|
|
|
The solution here is to return the `String` directly:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn no_dangle() -> String {
|
|
|
|
|
let s = String::from("hello");
|
|
|
|
|
|
|
|
|
|
s
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This works without any problems. Ownership is moved out, and nothing is
|
|
|
|
|
deallocated.
|
|
|
|
|
|
|
|
|
|
### The Rules of References
|
|
|
|
|
|
|
|
|
|
Let’s recap what we’ve discussed about references:
|
|
|
|
|
|
|
|
|
|
* At any given time, you can have *either* one mutable reference *or* any
|
2022-08-14 17:47:10 +00:00
|
|
|
|
number of immutable references.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
* References must always be valid.
|
2022-09-09 23:49:52 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
Next, we’ll look at a different kind of reference: slices.
|
|
|
|
|
|
|
|
|
|
## The Slice Type
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
*Slices* let you reference a contiguous sequence of elements in a collection
|
|
|
|
|
rather than the whole collection. A slice is a kind of reference, so it does
|
|
|
|
|
not have ownership.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-05-04 17:01:15 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
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 want
|
|
|
|
|
ownership, so this is fine. 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.
|
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
Filename: src/main.rs
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
```
|
2022-09-09 23:49:52 +00:00
|
|
|
|
fn first_word(s: &String) -> usize {
|
|
|
|
|
1 let bytes = s.as_bytes();
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
for (2 i, &item) in 3 bytes.iter().enumerate() {
|
|
|
|
|
4 if item == b' ' {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
5 s.len()
|
2021-07-26 01:49:50 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-7: The `first_word` function that returns a byte index value into the
|
2022-09-13 16:23:24 +00:00
|
|
|
|
`String` parameter
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Because we need to go through the `String` element by element and check whether
|
|
|
|
|
a value is a space, we’ll convert our `String` to an array of bytes using the
|
2021-11-18 22:28:57 +00:00
|
|
|
|
`as_bytes` method [1].
|
2022-05-04 17:01:15 +00:00
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
Next, we create an iterator over the array of bytes using the `iter` method
|
|
|
|
|
[3]. We’ll discuss iterators in more detail in Chapter 13. For now, know that
|
|
|
|
|
`iter` is a method that returns each element in a collection and that
|
|
|
|
|
`enumerate` wraps the result of `iter` and returns each element as part of a
|
|
|
|
|
tuple instead. The first element of the tuple returned from `enumerate` is the
|
|
|
|
|
index, and the second element is a reference to the element. This is a bit more
|
|
|
|
|
convenient than calculating the index ourselves.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Because the `enumerate` method returns a tuple, we can use patterns to
|
2021-11-18 22:38:12 +00:00
|
|
|
|
destructure that tuple. We’ll be discussing patterns more in Chapter 6. In the
|
|
|
|
|
`for` loop, we specify a pattern that has `i` for the index in the tuple and
|
|
|
|
|
`&item` for the single byte in the tuple [2]. Because we get a reference to the
|
2021-07-26 01:49:50 +00:00
|
|
|
|
element from `.iter().enumerate()`, we use `&` in the pattern.
|
|
|
|
|
|
|
|
|
|
Inside the `for` loop, we search for the byte that represents the space by
|
2021-11-18 22:28:57 +00:00
|
|
|
|
using the byte literal syntax [4]. If we find a space, we return the position.
|
|
|
|
|
Otherwise, we return the length of the string by using `s.len()` [5].
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
We now have a way to find out the index of the end of the first word in the
|
|
|
|
|
string, but there’s a problem. We’re returning a `usize` on its own, but it’s
|
|
|
|
|
only a meaningful number in the context of the `&String`. In other words,
|
|
|
|
|
because it’s a separate value from the `String`, there’s no guarantee that it
|
|
|
|
|
will still be valid in the future. Consider the program in Listing 4-8 that
|
|
|
|
|
uses the `first_word` function from Listing 4-7.
|
|
|
|
|
|
2022-08-24 13:12:29 +00:00
|
|
|
|
```
|
|
|
|
|
// src/main.rs
|
2021-07-26 01:49:50 +00:00
|
|
|
|
fn main() {
|
|
|
|
|
let mut s = String::from("hello world");
|
|
|
|
|
|
|
|
|
|
let word = first_word(&s); // word will get the value 5
|
|
|
|
|
|
|
|
|
|
s.clear(); // this empties the String, making it equal to ""
|
|
|
|
|
|
|
|
|
|
// word still has the value 5 here, but there's no more string that
|
|
|
|
|
// we could meaningfully use the value 5 with. word is now totally invalid!
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-8: Storing the result from calling the `first_word` function and then
|
2022-09-13 16:23:24 +00:00
|
|
|
|
changing the `String` contents
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
This program compiles without any errors and would also do so if we used `word`
|
|
|
|
|
after calling `s.clear()`. Because `word` isn’t connected to the state of `s`
|
|
|
|
|
at all, `word` still contains the value `5`. We could use that value `5` with
|
|
|
|
|
the variable `s` to try to extract the first word out, but this would be a bug
|
|
|
|
|
because the contents of `s` have changed since we saved `5` in `word`.
|
|
|
|
|
|
|
|
|
|
Having to worry about the index in `word` getting out of sync with the data in
|
|
|
|
|
`s` is tedious and error prone! Managing these indices is even more brittle if
|
|
|
|
|
we write a `second_word` function. Its signature would have to look like this:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn second_word(s: &String) -> (usize, usize) {
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Now we’re tracking a starting *and* an ending index, and we have even more
|
|
|
|
|
values that were calculated from data in a particular state but aren’t tied to
|
2022-08-14 17:47:10 +00:00
|
|
|
|
that state at all. We have three unrelated variables floating around that need
|
|
|
|
|
to be kept in sync.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```
|
2022-08-24 00:15:07 +00:00
|
|
|
|
let s = String::from("hello world");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-08-24 00:15:07 +00:00
|
|
|
|
let hello = &s[0..5];
|
|
|
|
|
let world = &s[6..11];
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
2021-11-18 22:38:12 +00:00
|
|
|
|
Rather than a reference to the entire `String`, `hello` is a reference to a
|
|
|
|
|
portion of the `String`, specified in the extra `[0..5]` bit. We create slices
|
|
|
|
|
using a range within brackets by specifying `[starting_index..ending_index]`,
|
|
|
|
|
where `starting_index` is the first position in the slice and `ending_index` is
|
|
|
|
|
one more than the last position in the slice. Internally, the slice data
|
|
|
|
|
structure stores the starting position and the length of the slice, which
|
2022-08-14 17:47:10 +00:00
|
|
|
|
corresponds to `ending_index` minus `starting_index`. So, in the case of `let
|
2021-11-18 22:38:12 +00:00
|
|
|
|
world = &s[6..11];`, `world` would be a slice that contains a pointer to the
|
2022-08-24 13:12:29 +00:00
|
|
|
|
byte at index 6 of `s` with a length value of `5`.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Figure 4-6 shows this in a diagram.
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Figure 4-6: String slice referring to part of a `String`
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
2022-09-09 23:57:06 +00:00
|
|
|
|
With Rust’s `..` range syntax, if you want to start at index 0, you can drop
|
|
|
|
|
the value before the two periods. In other words, these are equal:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let slice = &s[0..2];
|
|
|
|
|
let slice = &s[..2];
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
By the same token, if your slice includes the last byte of the `String`, you
|
|
|
|
|
can drop the trailing number. That means these are equal:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let s = String::from("hello");
|
|
|
|
|
|
|
|
|
|
let len = s.len();
|
|
|
|
|
|
|
|
|
|
let slice = &s[3..len];
|
|
|
|
|
let slice = &s[3..];
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
You can also drop both values to take a slice of the entire string. So these
|
|
|
|
|
are equal:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let s = String::from("hello");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let len = s.len();
|
|
|
|
|
|
|
|
|
|
let slice = &s[0..len];
|
|
|
|
|
let slice = &s[..];
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-09 23:49:52 +00:00
|
|
|
|
> Note: String slice range indices must occur at valid UTF-8 character
|
2022-08-14 17:47:10 +00:00
|
|
|
|
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 “Storing UTF-8 Encoded Text with
|
|
|
|
|
Strings” on page XX.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
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`:
|
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn first_word(s: &String) -> &str {
|
|
|
|
|
let bytes = s.as_bytes();
|
|
|
|
|
|
|
|
|
|
for (i, &item) in bytes.iter().enumerate() {
|
|
|
|
|
if item == b' ' {
|
|
|
|
|
return &s[0..i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
&s[..]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
We get the index for the end of the word the same way we did in Listing 4-7, by
|
|
|
|
|
looking for the first occurrence of a space. When we find a space, we return a
|
|
|
|
|
string slice using the start of the string and the index of the space as the
|
|
|
|
|
starting and ending indices.
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Now when we call `first_word`, we get back a single value that is tied to the
|
|
|
|
|
underlying data. The value is made up of a reference to the starting point of
|
|
|
|
|
the slice and the number of elements in the slice.
|
|
|
|
|
|
|
|
|
|
Returning a slice would also work for a `second_word` function:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn second_word(s: &String) -> &str {
|
|
|
|
|
```
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
We now have a straightforward API that’s much harder to mess up because the
|
2021-07-26 01:49:50 +00:00
|
|
|
|
compiler will ensure the references into the `String` remain valid. Remember
|
|
|
|
|
the bug in the program in Listing 4-8, when we got the index to the end of the
|
|
|
|
|
first word but then cleared the string so our index was invalid? That code was
|
|
|
|
|
logically incorrect but didn’t show any immediate errors. The problems would
|
|
|
|
|
show up later if we kept trying to use the first word index with an emptied
|
|
|
|
|
string. Slices make this bug impossible and let us know we have a problem with
|
|
|
|
|
our code much sooner. Using the slice version of `first_word` will throw a
|
|
|
|
|
compile-time error:
|
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let mut s = String::from("hello world");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let word = first_word(&s);
|
|
|
|
|
|
|
|
|
|
s.clear(); // error!
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
println!("the first word is: {word}");
|
2021-07-26 01:49:50 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Here’s the compiler error:
|
|
|
|
|
|
|
|
|
|
```
|
2021-11-18 22:38:12 +00:00
|
|
|
|
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as
|
|
|
|
|
immutable
|
2021-07-26 01:49:50 +00:00
|
|
|
|
--> src/main.rs:18:5
|
|
|
|
|
|
|
|
|
|
|
16 | let word = first_word(&s);
|
|
|
|
|
| -- immutable borrow occurs here
|
|
|
|
|
17 |
|
|
|
|
|
18 | s.clear(); // error!
|
|
|
|
|
| ^^^^^^^^^ mutable borrow occurs here
|
|
|
|
|
19 |
|
2022-08-15 01:23:58 +00:00
|
|
|
|
20 | println!("the first word is: {word}");
|
|
|
|
|
| ---- immutable borrow later used here
|
2021-07-26 01:49:50 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Recall from the borrowing rules that if we have an immutable reference to
|
|
|
|
|
something, we cannot also take a mutable reference. Because `clear` needs to
|
|
|
|
|
truncate the `String`, it needs to get a mutable reference. The `println!`
|
|
|
|
|
after the call to `clear` uses the reference in `word`, so the immutable
|
|
|
|
|
reference must still be active at that point. Rust disallows the mutable
|
|
|
|
|
reference in `clear` and the immutable reference in `word` from existing at the
|
|
|
|
|
same time, and compilation fails. Not only has Rust made our API easier to use,
|
|
|
|
|
but it has also eliminated an entire class of errors at compile time!
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
#### String Literals as Slices
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Recall that we talked about string literals being stored inside the binary. Now
|
|
|
|
|
that we know about slices, we can properly understand string literals:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let s = "Hello, world!";
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The type of `s` here is `&str`: it’s a slice pointing to that specific point of
|
|
|
|
|
the binary. This is also why string literals are immutable; `&str` is an
|
|
|
|
|
immutable reference.
|
|
|
|
|
|
|
|
|
|
#### String Slices as Parameters
|
|
|
|
|
|
|
|
|
|
Knowing that you can take slices of literals and `String` values leads us to
|
|
|
|
|
one more improvement on `first_word`, and that’s its signature:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn first_word(s: &String) -> &str {
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
A more experienced Rustacean would write the signature shown in Listing 4-9
|
|
|
|
|
instead because it allows us to use the same function on both `&String` values
|
|
|
|
|
and `&str` values.
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn first_word(s: &str) -> &str {
|
|
|
|
|
```
|
|
|
|
|
|
2022-09-13 16:34:49 +00:00
|
|
|
|
Listing 4-9: Improving the `first_word` function by using a string slice for
|
|
|
|
|
the type of the `s` parameter
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
If we have a string slice, we can pass that directly. If we have a `String`, we
|
|
|
|
|
can pass a slice of the `String` or a reference to the `String`. This
|
|
|
|
|
flexibility takes advantage of *deref coercions*, a feature we will cover in
|
2022-08-14 17:47:10 +00:00
|
|
|
|
“Implicit Deref Coercions with Functions and Methods” on page XX.
|
|
|
|
|
|
|
|
|
|
Defining a function to take a string slice instead of a reference to a `String`
|
|
|
|
|
makes our API more general and useful without losing any functionality:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
Filename: src/main.rs
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
fn main() {
|
|
|
|
|
let my_string = String::from("hello world");
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
// `first_word` works on slices of `String`s, whether partial
|
|
|
|
|
// or whole
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let word = first_word(&my_string[0..6]);
|
|
|
|
|
let word = first_word(&my_string[..]);
|
2022-08-15 01:23:58 +00:00
|
|
|
|
// `first_word` also works on references to `String`s, which
|
|
|
|
|
// are equivalent to whole slices of `String`s
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let word = first_word(&my_string);
|
|
|
|
|
|
|
|
|
|
let my_string_literal = "hello world";
|
|
|
|
|
|
2022-08-15 01:23:58 +00:00
|
|
|
|
// `first_word` works on slices of string literals,
|
|
|
|
|
// whether partial or whole
|
2021-07-26 01:49:50 +00:00
|
|
|
|
let word = first_word(&my_string_literal[0..6]);
|
|
|
|
|
let word = first_word(&my_string_literal[..]);
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
// Because string literals *are* string slices already,
|
|
|
|
|
// this works too, without the slice syntax!
|
|
|
|
|
let word = first_word(my_string_literal);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Other Slices
|
|
|
|
|
|
|
|
|
|
String slices, as you might imagine, are specific to strings. But there’s a
|
2022-08-14 17:47:10 +00:00
|
|
|
|
more general slice type too. Consider this array:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let a = [1, 2, 3, 4, 5];
|
|
|
|
|
```
|
|
|
|
|
|
2022-08-14 17:47:10 +00:00
|
|
|
|
Just as we might want to refer to part of a string, we might want to refer to
|
|
|
|
|
part of an array. We’d do so like this:
|
2021-07-26 01:49:50 +00:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
let a = [1, 2, 3, 4, 5];
|
|
|
|
|
|
|
|
|
|
let slice = &a[1..3];
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|
2021-07-26 01:49:50 +00:00
|
|
|
|
assert_eq!(slice, &[2, 3]);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This slice has the type `&[i32]`. It works the same way as string slices do, by
|
|
|
|
|
storing a reference to the first element and a length. You’ll use this kind of
|
|
|
|
|
slice for all sorts of other collections. We’ll discuss these collections in
|
|
|
|
|
detail when we talk about vectors in Chapter 8.
|
|
|
|
|
|
|
|
|
|
## Summary
|
|
|
|
|
|
|
|
|
|
The concepts of ownership, borrowing, and slices ensure memory safety in Rust
|
|
|
|
|
programs at compile time. The Rust language gives you control over your memory
|
|
|
|
|
usage in the same way as other systems programming languages, but having the
|
|
|
|
|
owner of data automatically clean up that data when the owner goes out of scope
|
|
|
|
|
means you don’t have to write and debug extra code to get this control.
|
|
|
|
|
|
|
|
|
|
Ownership affects how lots of other parts of Rust work, so we’ll talk about
|
|
|
|
|
these concepts further throughout the rest of the book. Let’s move on to
|
|
|
|
|
Chapter 5 and look at grouping pieces of data together in a `struct`.
|
2022-08-14 17:47:10 +00:00
|
|
|
|
|