Skip to content

Guide: ownership #16487

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 21, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions src/doc/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -3642,6 +3642,173 @@ In order to truly understand this error, we have to learn a few new concepts:

## Ownership, borrowing, and lifetimes

Whenever a resource of some kind is created, something must be responsible
for destroying that resource as well. Given that we're discussing pointers
right now, let's discuss this in the context of memory allocation, though
it applies to other resources as well.

When you allocate heap memory, you need a mechanism to free that memory. Many
languages let the programmer control the allocation, and then use a garbage
collector to handle the deallocation. This is a valid, time-tested strategy,
but it's not without its drawbacks. Because the programmer does not have to
think as much about deallocation, allocation becomes something commonplace,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to explain why "allocation becomes something commonplace" is bad?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the next sentence explained that. Maybe I can make it more clear somehow?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most languages with a garbage collector also make allocation easy - many languages don't even define if something is going to be stack allocated or heap allocated, and leave it 100% up to the discretion of the compiler/interpreter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I mentioned how garbage collectors make deallocation imprecise, and then this next sentence says "if you need precise control..."

I'm not saying this doesn't need re-worded, I'm just trying to understand exactly how to re-write it to make it more clear.

because it's easy. And if you need precise control over when something is
deallocated, leaving it up to your runtime can make this difficult.

Rust chooses a different path, and that path is called **ownership**. Any
binding that creates a resource is the **owner** of that resource. Being an
owner gives you three privileges, with two restrictions:

1. You control when that resource is deallocated.
2. You may lend that resource, immutably, to as many borrowers as you'd like.
3. You may lend that resource, mutably, to a single borrower. **BUT**
4. Once you've done so, you may not also lend it out otherwise, mutably or
immutably.
5. You may not lend it out mutably if you're currently lending it to someone.

What's up with all this 'lending' and 'borrowing'? When you allocate memory,
you get a pointer to that memory. This pointer allows you to manipulate said
memory. If you are the owner of a pointer, then you may allow another
binding to temporarily borrow that pointer, and then they can manipulate the
memory. The length of time that the borrower is borrowing the pointer
from you is called a **lifetime**.

If two distinct bindings share a pointer, and the memory that pointer points to
is immutable, then there are no problems. But if it's mutable, both pointers
can attempt to write to the memory at the same time, causing a **race
condition**. Therefore, if someone wants to mutate something that they've
borrowed from you, you must not have lent out that pointer to anyone else.

Rust has a sophisticated system called the **borrow checker** to make sure that
everyone plays by these rules. At compile time, it verifies that none of these
rules are broken. If there's no problem, our program compiles successfully, and
there is no runtime overhead for any of this. The borrow checker works only at
compile time. If the borrow checker did find a problem, it will report a
**lifetime error**, and your program will refuse to compile.

That's a lot to take in. It's also one of the _most_ important concepts in
all of Rust. Let's see this syntax in action:

```{rust}
{
let x = 5i; // x is the owner of this integer, which is memory on the stack.

// other code here...

} // privilege 1: when x goes out of scope, this memory is deallocated

/// this function borrows an integer. It's given back automatically when the
/// function returns.
fn foo(x: &int) -> &int { x }

{
let x = 5i; // x is the owner of this integer, which is memory on the stack.

// privilege 2: you may lend that resource, to as many borrowers as you'd like
let y = &x;
let z = &x;

foo(&x); // functions can borrow too!

let a = &x; // we can do this alllllll day!
}

{
let mut x = 5i; // x is the owner of this integer, which is memory on the stack.

let y = &mut x; // privilege 3: you may lend that resource to a single borrower,
// mutably
}
```

If you are a borrower, you get a few privileges as well, but must also obey a
restriction:

1. If the borrow is immutable, you may read the data the pointer points to.
2. If the borrow is mutable, you may read and write the data the pointer points to.
3. You may lend the pointer to someone else in an immutable fashion, **BUT**
4. When you do so, they must return it to you before you must give your own
borrow back.

This last requirement can seem odd, but it also makes sense. If you have to
return something, and you've lent it to someone, they need to give it back to
you for you to give it back! If we didn't, then the owner could deallocate
the memory, and the person we've loaned it out to would have a pointer to
invalid memory. This is called a 'dangling pointer.'

Let's re-examine the error that led us to talk about all of this, which was a
violation of the restrictions placed on owners who lend something out mutably.
The code:

```{rust,ignore}
let mut x = 5i;
let y = &mut x;
let z = &mut x;
```

The error:

```{notrust,ignore}
error: cannot borrow `x` as mutable more than once at a time
let z = &mut x;
^
note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends
let y = &mut x;
^
note: previous borrow ends here
fn main() {
let mut x = 5i;
let y = &mut x;
let z = &mut x;
}
^
```

This error comes in three parts. Let's go over each in turn.

```{notrust,ignore}
error: cannot borrow `x` as mutable more than once at a time
let z = &mut x;
^
```

This error states the restriction: you cannot lend out something mutable more
than once at the same time. The borrow checker knows the rules!

```{notrust,ignore}
note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends
let y = &mut x;
^
```

Some compiler errors come with notes to help you fix the error. This error comes
with two notes, and this is the first. This note informs us of exactly where
the first mutable borrow occurred. The error showed us the second. So now we
see both parts of the problem. It also alludes to rule #3, by reminding us that
we can't change `x` until the borrow is over.

```{notrust,ignore}
note: previous borrow ends here
fn main() {
let mut x = 5i;
let y = &mut x;
let z = &mut x;
}
^
```

Here's the second note, which lets us know where the first borrow would be over.
This is useful, because if we wait to try to borrow `x` after this borrow is
over, then everything will work.

These rules are very simple, but that doesn't mean that they're easy. For more
advanced patterns, please consult the [Lifetime Guide](guide-lifetimes.html).
You'll also learn what this type signature with the `'a` syntax is:

```{rust,ignore}
pub fn as_maybe_owned(&self) -> MaybeOwned<'a> { ... }
```

## Boxes

All of our references so far have been to variables we've created on the stack.
Expand Down