2015-01-16 14:30:27 -06:00
|
|
|
|
% Ownership
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
This guide is one of three presenting Rust’s ownership system. This is one of
|
|
|
|
|
Rust’s most unique and compelling features, with which Rust developers should
|
|
|
|
|
become quite acquainted. Ownership is how Rust achieves its largest goal,
|
2015-05-07 17:42:10 -05:00
|
|
|
|
memory safety. There are a few distinct concepts, each with its own
|
2015-04-24 15:43:36 -05:00
|
|
|
|
chapter:
|
|
|
|
|
|
|
|
|
|
* ownership, which you’re reading now.
|
|
|
|
|
* [borrowing][borrowing], and their associated feature ‘references’
|
|
|
|
|
* [lifetimes][lifetimes], an advanced concept of borrowing
|
|
|
|
|
|
|
|
|
|
These three chapters are related, and in order. You’ll need all three to fully
|
|
|
|
|
understand the ownership system.
|
|
|
|
|
|
|
|
|
|
[borrowing]: references-and-borrowing.html
|
|
|
|
|
[lifetimes]: lifetimes.html
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
# Meta
|
|
|
|
|
|
|
|
|
|
Before we get to the details, two important notes about the ownership system.
|
|
|
|
|
|
|
|
|
|
Rust has a focus on safety and speed. It accomplishes these goals through many
|
2015-04-24 15:43:36 -05:00
|
|
|
|
‘zero-cost abstractions’, which means that in Rust, abstractions cost as little
|
2014-11-04 01:52:36 -06:00
|
|
|
|
as possible in order to make them work. The ownership system is a prime example
|
2015-04-24 15:43:36 -05:00
|
|
|
|
of a zero cost abstraction. All of the analysis we’ll talk about in this guide
|
2014-11-04 01:52:36 -06:00
|
|
|
|
is _done at compile time_. You do not pay any run-time cost for any of these
|
|
|
|
|
features.
|
|
|
|
|
|
|
|
|
|
However, this system does have a certain cost: learning curve. Many new users
|
2015-04-24 15:43:36 -05:00
|
|
|
|
to Rust experience something we like to call ‘fighting with the borrow
|
|
|
|
|
checker’, where the Rust compiler refuses to compile a program that the author
|
|
|
|
|
thinks is valid. This often happens because the programmer’s mental model of
|
|
|
|
|
how ownership should work doesn’t match the actual rules that Rust implements.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
You probably will experience similar things at first. There is good news,
|
|
|
|
|
however: more experienced Rust developers report that once they work with the
|
|
|
|
|
rules of the ownership system for a period of time, they fight the borrow
|
|
|
|
|
checker less and less.
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
With that in mind, let’s learn about ownership.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
# Ownership
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
[`Variable bindings`][bindings] have a property in Rust: they ‘have ownership’
|
|
|
|
|
of what they’re bound to. This means that when a binding goes out of scope, the
|
|
|
|
|
resource that they’re bound to are freed. For example:
|
2012-09-15 19:09:21 -05:00
|
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```rust
|
2015-04-24 15:43:36 -05:00
|
|
|
|
fn foo() {
|
|
|
|
|
let v = vec![1, 2, 3];
|
2012-09-15 19:09:21 -05:00
|
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
When `v` comes into scope, a new [`Vec<T>`][vect] is created. In this case, the
|
|
|
|
|
vector also allocates space on [the heap][heap], for the three elements. When
|
|
|
|
|
`v` goes out of scope at the end of `foo()`, Rust will clean up everything
|
|
|
|
|
related to the vector, even the heap-allocated memory. This happens
|
|
|
|
|
deterministically, at the end of the scope.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
[vect]: ../std/vec/struct.Vec.html
|
|
|
|
|
[heap]: the-stack-and-the-heap.html
|
2015-05-07 17:42:10 -05:00
|
|
|
|
[bindings]: variable-bindings.html
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
# Move semantics
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
There’s some more subtlety here, though: Rust ensures that there is _exactly
|
|
|
|
|
one_ binding to any given resource. For example, if we have a vector, we can
|
|
|
|
|
assign it to another binding:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
```rust
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v = vec![1, 2, 3];
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v2 = v;
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
But, if we try to use `v` afterwards, we get an error:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
```rust,ignore
|
|
|
|
|
let v = vec![1, 2, 3];
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v2 = v;
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
println!("v[0] is: {}", v[0]);
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
It looks like this:
|
2015-01-12 12:48:59 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
```text
|
|
|
|
|
error: use of moved value: `v`
|
|
|
|
|
println!("v[0] is: {}", v[0]);
|
|
|
|
|
^
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
A similar thing happens if we define a function which takes ownership, and
|
|
|
|
|
try to use something after we’ve passed it as an argument:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
```rust,ignore
|
|
|
|
|
fn take(v: Vec<i32>) {
|
|
|
|
|
// what happens here isn’t important.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v = vec![1, 2, 3];
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
take(v);
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
println!("v[0] is: {}", v[0]);
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
Same error: “use of moved value.” When we transfer ownership to something else,
|
|
|
|
|
we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of
|
|
|
|
|
special annotation here, it’s the default thing that Rust does.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
## The details
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
The reason that we cannot use a binding after we’ve moved it is subtle, but
|
|
|
|
|
important. When we write code like this:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
```rust
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v = vec![1, 2, 3];
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v2 = v;
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
The first line creates some data for the vector on the [stack][sh], `v`. The
|
|
|
|
|
vector’s data, however, is stored on the [heap][sh], and so it contains a
|
2015-05-07 18:43:18 -05:00
|
|
|
|
pointer to that data. When we move `v` to `v2`, it creates a copy of that pointer,
|
2015-04-24 15:43:36 -05:00
|
|
|
|
for `v2`. Which would mean two pointers to the contents of the vector on the
|
|
|
|
|
heap. That would be a problem: it would violate Rust’s safety guarantees by
|
|
|
|
|
introducing a data race. Therefore, Rust forbids using `v` after we’ve done the
|
|
|
|
|
move.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
[sh]: the-stack-and-the-heap.html
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
It’s also important to note that optimizations may remove the actual copy of
|
|
|
|
|
the bytes, depending on circumstances. So it may not be as inefficient as it
|
|
|
|
|
initially seems.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
## `Copy` types
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
We’ve established that when ownership is transferred to another binding, you
|
|
|
|
|
cannot use the original binding. However, there’s a [trait][traits] that changes this
|
|
|
|
|
behavior, and it’s called `Copy`. We haven’t discussed traits yet, but for now,
|
|
|
|
|
you can think of them as an annotation to a particular type that adds extra
|
|
|
|
|
behavior. For example:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
```rust
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v = 1;
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v2 = v;
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
println!("v is: {}", v);
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
In this case, `v` is an `i32`, which implements the `Copy` trait. This means
|
|
|
|
|
that, just like a move, when we assign `v` to `v2`, a copy of the data is made.
|
|
|
|
|
But, unlike a move, we can still use `v` afterward. This is because an `i32`
|
|
|
|
|
has no pointers to data somewhere else, copying it is a full copy.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
We will discuss how to make your own types `Copy` in the [traits][traits]
|
|
|
|
|
section.
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
[traits]: traits.html
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
# More than ownership
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
Of course, if we had to hand ownership back with every function we wrote:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
```rust
|
2015-04-24 15:43:36 -05:00
|
|
|
|
fn foo(v: Vec<i32>) -> Vec<i32> {
|
|
|
|
|
// do stuff with v
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
// hand back ownership
|
|
|
|
|
v
|
2014-11-04 01:52:36 -06:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-05-07 14:31:10 -05:00
|
|
|
|
This would get very tedious. It gets worse the more things we want to take ownership of:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
|
|
```rust
|
2015-04-24 15:43:36 -05:00
|
|
|
|
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
|
|
|
|
|
// do stuff with v1 and v2
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
// hand back ownership, and the result of our function
|
|
|
|
|
(v1, v2, 42)
|
2014-11-04 01:52:36 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let v1 = vec![1, 2, 3];
|
|
|
|
|
let v2 = vec![1, 2, 3];
|
2012-09-15 19:09:21 -05:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
let (v1, v2, answer) = foo(v1, v2);
|
2014-11-04 01:52:36 -06:00
|
|
|
|
```
|
2014-03-23 15:05:01 -05:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
Ugh! The return type, return line, and calling the function gets way more
|
|
|
|
|
complicated.
|
2014-12-11 10:37:20 -06:00
|
|
|
|
|
2015-04-24 15:43:36 -05:00
|
|
|
|
Luckily, Rust offers a feature, borrowing, which helps us solve this problem.
|
|
|
|
|
It’s the topic of the next section!
|
2014-12-11 10:37:20 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-09-15 19:09:21 -05:00
|
|
|
|
|