2014-11-04 01:52:36 -06:00
|
|
|
% The Rust Ownership Guide
|
|
|
|
|
|
|
|
This guide presents 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, memory safety.
|
|
|
|
The ownership system has a few distinct concepts: **ownership**, **borrowing**,
|
|
|
|
and **lifetimes**. We'll talk about each one in turn.
|
|
|
|
|
|
|
|
# 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
|
|
|
|
"zero cost abstractions," which means that in Rust, abstractions cost as little
|
|
|
|
as possible in order to make them work. The ownership system is a prime example
|
|
|
|
of a zero cost abstraction. All of the analysis we'll talk about in this guide
|
|
|
|
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
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
|
|
|
|
With that in mind, let's learn about ownership.
|
|
|
|
|
|
|
|
# Ownership
|
|
|
|
|
|
|
|
At its core, ownership is about 'resources.' For the purposes of the vast
|
|
|
|
majority of this guide, we will talk about a specific resource: memory. The
|
|
|
|
concept generalizes to any kind of resource, like a file handle, but to make it
|
|
|
|
more concrete, we'll focus on memory.
|
|
|
|
|
|
|
|
When your program allocates some memory, it needs some way to deallocate that
|
|
|
|
memory. Imagine a function `foo` that allocates four bytes of memory, and then
|
|
|
|
never deallocates that memory. We call this problem 'leaking' memory, because
|
|
|
|
each time we call `foo`, we're allocating another four bytes. Eventually, with
|
|
|
|
enough calls to `foo`, we will run our system out of memory. That's no good. So
|
|
|
|
we need some way for `foo` to deallocate those four bytes. It's also important
|
|
|
|
that we don't deallocate too many times, either. Without getting into the
|
|
|
|
details, attempting to deallocate memory multiple times can lead to problems.
|
|
|
|
In other words, any time some memory is allocated, we need to make sure that we
|
|
|
|
deallocate that memory once and only once. Too many times is bad, not enough
|
|
|
|
times is bad. The counts must match.
|
|
|
|
|
|
|
|
There's one other important detail with regards to allocating memory. Whenever
|
|
|
|
we request some amount of memory, what we are given is a handle to that memory.
|
|
|
|
This handle (often called a 'pointer', when we're referring to memory) is how
|
|
|
|
we interact with the allocated memory. As long as we have that handle, we can
|
|
|
|
do something with the memory. Once we're done with the handle, we're also done
|
|
|
|
with the memory, as we can't do anything useful without a handle to it.
|
|
|
|
|
|
|
|
Historically, systems programming languages require you to track these
|
|
|
|
allocations, deallocations, and handles yourself. For example, if we want some
|
|
|
|
memory from the heap in a language like C, we do this:
|
|
|
|
|
|
|
|
```c
|
|
|
|
{
|
|
|
|
int *x = malloc(sizeof(int));
|
|
|
|
|
|
|
|
// we can now do stuff with our handle x
|
|
|
|
*x = 5;
|
|
|
|
|
|
|
|
free(x);
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
2012-09-15 19:09:21 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
The call to `malloc` allocates some memory. The call to `free` deallocates the
|
|
|
|
memory. There's also bookkeeping about allocating the correct amount of memory.
|
|
|
|
|
|
|
|
Rust combines these two aspects of allocating memory (and other resources) into
|
|
|
|
a concept called 'ownership.' Whenever we request some memory, that handle we
|
|
|
|
receive is called the 'owning handle.' Whenever that handle goes out of scope,
|
|
|
|
Rust knows that you cannot do anything with the memory anymore, and so
|
|
|
|
therefore deallocates the memory for you. Here's the equivalent example in
|
|
|
|
Rust:
|
2012-09-15 19:09:21 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
```rust
|
|
|
|
{
|
|
|
|
let x = box 5i;
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
The `box` keyword creates a `Box<T>` (specifically `Box<int>` in this case) by
|
|
|
|
allocating a small segment of memory on the heap with enough space to fit an
|
|
|
|
`int`. But where in the code is the box deallocated? We said before that we
|
|
|
|
must have a deallocation for each allocation. Rust handles this for you. It
|
|
|
|
knows that our handle, `x`, is the owning reference to our box. Rust knows that
|
|
|
|
`x` will go out of scope at the end of the block, and so it inserts a call to
|
|
|
|
deallocate the memory at the end of the scope. Because the compiler does this
|
2014-12-05 19:14:28 -06:00
|
|
|
for us, it's impossible to forget. We always have exactly one deallocation paired
|
2014-11-04 01:52:36 -06:00
|
|
|
with each of our allocations.
|
|
|
|
|
|
|
|
This is pretty straightforward, but what happens when we want to pass our box
|
|
|
|
to a function? Let's look at some code:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn main() {
|
|
|
|
let x = box 5i;
|
|
|
|
|
|
|
|
add_one(x);
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
fn add_one(mut num: Box<int>) {
|
|
|
|
*num += 1;
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
This code works, but it's not ideal. For example, let's add one more line of
|
|
|
|
code, where we print out the value of `x`:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn main() {
|
|
|
|
let x = box 5i;
|
|
|
|
|
|
|
|
add_one(x);
|
|
|
|
|
|
|
|
println!("{}", x);
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
fn add_one(mut num: Box<int>) {
|
|
|
|
*num += 1;
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
This does not compile, and gives us an error:
|
|
|
|
|
2014-12-10 14:12:16 -06:00
|
|
|
```text
|
2014-11-04 01:52:36 -06:00
|
|
|
error: use of moved value: `x`
|
|
|
|
println!("{}", x);
|
|
|
|
^
|
|
|
|
```
|
|
|
|
|
|
|
|
Remember, we need one deallocation for every allocation. When we try to pass
|
|
|
|
our box to `add_one`, we would have two handles to the memory: `x` in `main`,
|
|
|
|
and `num` in `add_one`. If we deallocated the memory when each handle went out
|
|
|
|
of scope, we would have two deallocations and one allocation, and that's wrong.
|
|
|
|
So when we call `add_one`, Rust defines `num` as the owner of the handle. And
|
|
|
|
so, now that we've given ownership to `num`, `x` is invalid. `x`'s value has
|
|
|
|
"moved" from `x` to `num`. Hence the error: use of moved value `x`.
|
|
|
|
|
|
|
|
To fix this, we can have `add_one` give ownership back when it's done with the
|
|
|
|
box:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn main() {
|
|
|
|
let x = box 5i;
|
|
|
|
|
|
|
|
let y = add_one(x);
|
|
|
|
|
|
|
|
println!("{}", y);
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
fn add_one(mut num: Box<int>) -> Box<int> {
|
|
|
|
*num += 1;
|
|
|
|
|
|
|
|
num
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This code will compile and run just fine. Now, we return a `box`, and so the
|
|
|
|
ownership is transferred back to `y` in `main`. We only have ownership for the
|
|
|
|
duration of our function before giving it back. This pattern is very common,
|
|
|
|
and so Rust introduces a concept to describe a handle which temporarily refers
|
|
|
|
to something another handle owns. It's called "borrowing," and it's done with
|
|
|
|
"references", designated by the `&` symbol.
|
|
|
|
|
|
|
|
# Borrowing
|
|
|
|
|
|
|
|
Here's the current state of our `add_one` function:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn add_one(mut num: Box<int>) -> Box<int> {
|
|
|
|
*num += 1;
|
|
|
|
|
|
|
|
num
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This function takes ownership, because it takes a `Box`, which owns its
|
|
|
|
contents. But then we give ownership right back.
|
|
|
|
|
|
|
|
In the physical world, you can give one of your possessions to someone for a
|
2014-12-05 19:14:28 -06:00
|
|
|
short period of time. You still own your possession, you're just letting someone
|
2014-11-04 01:52:36 -06:00
|
|
|
else use it for a while. We call that 'lending' something to someone, and that
|
|
|
|
person is said to be 'borrowing' that something from you.
|
|
|
|
|
2014-12-05 19:14:28 -06:00
|
|
|
Rust's ownership system also allows an owner to lend out a handle for a limited
|
2014-11-04 01:52:36 -06:00
|
|
|
period. This is also called 'borrowing.' Here's a version of `add_one` which
|
|
|
|
borrows its argument rather than taking ownership:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn add_one(num: &mut int) {
|
|
|
|
*num += 1;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This function borrows an `int` from its caller, and then increments it. When
|
|
|
|
the function is over, and `num` goes out of scope, the borrow is over.
|
|
|
|
|
|
|
|
# Lifetimes
|
|
|
|
|
|
|
|
Lending out a reference to a resource that someone else owns can be
|
|
|
|
complicated, however. For example, imagine this set of operations:
|
|
|
|
|
2014-12-13 10:56:19 -06:00
|
|
|
1. I acquire a handle to some kind of resource.
|
2014-11-04 01:52:36 -06:00
|
|
|
2. I lend you a reference to the resource.
|
|
|
|
3. I decide I'm done with the resource, and deallocate it, while you still have
|
|
|
|
your reference.
|
|
|
|
4. You decide to use the resource.
|
|
|
|
|
|
|
|
Uh oh! Your reference is pointing to an invalid resource. This is called a
|
|
|
|
"dangling pointer" or "use after free," when the resource is memory.
|
|
|
|
|
|
|
|
To fix this, we have to make sure that step four never happens after step
|
|
|
|
three. The ownership system in Rust does this through a concept called
|
|
|
|
"lifetimes," which describe the scope that a reference is valid for.
|
|
|
|
|
|
|
|
Let's look at that function which borrows an `int` again:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn add_one(num: &int) -> int {
|
|
|
|
*num + 1
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Rust has a feature called 'lifetime elision,' which allows you to not write
|
2014-12-11 10:37:20 -06:00
|
|
|
lifetime annotations in certain circumstances. This is one of them. We will
|
|
|
|
cover the others later. Without eliding the lifetimes, `add_one` looks like
|
|
|
|
this:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
```rust
|
|
|
|
fn add_one<'a>(num: &'a int) -> int {
|
|
|
|
*num + 1
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The `'a` is called a **lifetime**. Most lifetimes are used in places where
|
|
|
|
short names like `'a`, `'b` and `'c` are clearest, but it's often useful to
|
|
|
|
have more descriptive names. Let's dig into the syntax in a bit more detail:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn add_one<'a>(...)
|
|
|
|
```
|
|
|
|
|
|
|
|
This part _declares_ our lifetimes. This says that `add_one` has one lifetime,
|
|
|
|
`'a`. If we had two, it would look like this:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn add_two<'a, 'b>(...)
|
|
|
|
```
|
|
|
|
|
2014-12-05 19:14:28 -06:00
|
|
|
Then in our parameter list, we use the lifetimes we've named:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
...(num: &'a int) -> ...
|
|
|
|
```
|
|
|
|
|
|
|
|
If you compare `&int` to `&'a int`, they're the same, it's just that the
|
|
|
|
lifetime `'a` has snuck in between the `&` and the `int`. We read `&int` as "a
|
|
|
|
reference to an int" and `&'a int` as "a reference to an int with the lifetime 'a.'"
|
|
|
|
|
|
|
|
Why do lifetimes matter? Well, for example, here's some code:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
struct Foo<'a> {
|
|
|
|
x: &'a int,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let y = &5i; // this is the same as `let _y = 5; let y = &_y;
|
|
|
|
let f = Foo { x: y };
|
|
|
|
|
|
|
|
println!("{}", f.x);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2014-12-05 19:14:28 -06:00
|
|
|
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
```{rust}
|
|
|
|
struct Foo<'a> {
|
|
|
|
# x: &'a int,
|
2012-09-15 20:06:20 -05:00
|
|
|
# }
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
declares a lifetime, and
|
|
|
|
|
|
|
|
```rust
|
|
|
|
# struct Foo<'a> {
|
|
|
|
x: &'a int,
|
2012-09-15 20:06:20 -05:00
|
|
|
# }
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
|
|
|
|
2014-12-05 19:14:28 -06:00
|
|
|
uses it. So why do we need a lifetime here? We need to ensure that any reference
|
2014-11-04 01:52:36 -06:00
|
|
|
to a `Foo` cannot outlive the reference to an `int` it contains.
|
|
|
|
|
|
|
|
## Thinking in scopes
|
|
|
|
|
|
|
|
A way to think about lifetimes is to visualize the scope that a reference is
|
|
|
|
valid for. For example:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn main() {
|
|
|
|
let y = &5i; // -+ y goes into scope
|
|
|
|
// |
|
|
|
|
// stuff // |
|
|
|
|
// |
|
|
|
|
} // -+ y goes out of scope
|
|
|
|
```
|
|
|
|
|
|
|
|
Adding in our `Foo`:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
struct Foo<'a> {
|
|
|
|
x: &'a int,
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let y = &5i; // -+ y goes into scope
|
|
|
|
let f = Foo { x: y }; // -+ f goes into scope
|
|
|
|
// stuff // |
|
|
|
|
// |
|
2014-12-17 19:01:37 -06:00
|
|
|
} // -+ f and y go out of scope
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
Our `f` lives within the scope of `y`, so everything works. What if it didn't?
|
|
|
|
This code won't work:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
struct Foo<'a> {
|
|
|
|
x: &'a int,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let x; // -+ x goes into scope
|
|
|
|
// |
|
|
|
|
{ // |
|
|
|
|
let y = &5i; // ---+ y goes into scope
|
|
|
|
let f = Foo { x: y }; // ---+ f goes into scope
|
2014-12-14 12:09:42 -06:00
|
|
|
x = &f.x; // | | error here
|
2014-12-17 19:01:37 -06:00
|
|
|
} // ---+ f and y go out of scope
|
2014-11-04 01:52:36 -06:00
|
|
|
// |
|
|
|
|
println!("{}", x); // |
|
|
|
|
} // -+ x goes out of scope
|
|
|
|
```
|
|
|
|
|
|
|
|
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
|
|
|
|
of `x`. But when we do `x = &f.x`, we make `x` a reference to something that's
|
|
|
|
about to go out of scope.
|
|
|
|
|
|
|
|
Named lifetimes are a way of giving these scopes a name. Giving something a
|
|
|
|
name is the first step towards being able to talk about it.
|
|
|
|
|
|
|
|
## 'static
|
|
|
|
|
|
|
|
The lifetime named 'static' is a special lifetime. It signals that something
|
|
|
|
has the lifetime of the entire program. Most Rust programmers first come across
|
|
|
|
`'static` when dealing with strings:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
let x: &'static str = "Hello, world.";
|
|
|
|
```
|
|
|
|
|
|
|
|
String literals have the type `&'static str` because the reference is always
|
|
|
|
alive: they are baked into the data segment of the final binary. Another
|
|
|
|
example are globals:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
static FOO: int = 5i;
|
|
|
|
let x: &'static int = &FOO;
|
|
|
|
```
|
|
|
|
|
|
|
|
This adds an `int` to the data segment of the binary, and FOO is a reference to
|
|
|
|
it.
|
|
|
|
|
|
|
|
# Shared Ownership
|
|
|
|
|
|
|
|
In all the examples we've considered so far, we've assumed that each handle has
|
|
|
|
a singular owner. But sometimes, this doesn't work. Consider a car. Cars have
|
|
|
|
four wheels. We would want a wheel to know which car it was attached to. But
|
|
|
|
this won't work:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
struct Car {
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Wheel {
|
|
|
|
size: int,
|
|
|
|
owner: Car,
|
2012-09-15 19:09:21 -05:00
|
|
|
}
|
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
fn main() {
|
2014-12-17 19:01:37 -06:00
|
|
|
let car = Car { name: "DeLorean".to_string() };
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
for _ in range(0u, 4) {
|
|
|
|
Wheel { size: 360, owner: car };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
We try to make four `Wheel`s, each with a `Car` that it's attached to. But the
|
|
|
|
compiler knows that on the second iteration of the loop, there's a problem:
|
|
|
|
|
2014-12-10 14:12:16 -06:00
|
|
|
```text
|
2014-11-04 01:52:36 -06:00
|
|
|
error: use of moved value: `car`
|
|
|
|
Wheel { size: 360, owner: car };
|
|
|
|
^~~
|
|
|
|
note: `car` moved here because it has type `Car`, which is non-copyable
|
|
|
|
Wheel { size: 360, owner: car };
|
|
|
|
^~~
|
|
|
|
```
|
|
|
|
|
|
|
|
We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with
|
2014-12-07 15:02:17 -06:00
|
|
|
`Box<T>`, because it has a single owner. We can do it with `Rc<T>` instead:
|
2014-11-04 01:52:36 -06:00
|
|
|
|
|
|
|
```rust
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
struct Car {
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Wheel {
|
|
|
|
size: int,
|
|
|
|
owner: Rc<Car>,
|
|
|
|
}
|
2012-09-15 19:09:21 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
fn main() {
|
2014-12-17 19:01:37 -06:00
|
|
|
let car = Car { name: "DeLorean".to_string() };
|
2014-03-23 15:05:01 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
let car_owner = Rc::new(car);
|
2014-03-23 15:05:01 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
for _ in range(0u, 4) {
|
|
|
|
Wheel { size: 360, owner: car_owner.clone() };
|
2014-03-23 15:05:01 -05:00
|
|
|
}
|
|
|
|
}
|
2014-11-04 01:52:36 -06:00
|
|
|
```
|
2014-03-23 15:05:01 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
We wrap our `Car` in an `Rc<T>`, getting an `Rc<Car>`, and then use the
|
|
|
|
`clone()` method to make new references. We've also changed our `Wheel` to have
|
|
|
|
an `Rc<Car>` rather than just a `Car`.
|
2014-03-23 20:24:17 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
This is the simplest kind of multiple ownership possible. For example, there's
|
|
|
|
also `Arc<T>`, which uses more expensive atomic instructions to be the
|
|
|
|
thread-safe counterpart of `Rc<T>`.
|
2014-03-23 20:24:17 -05:00
|
|
|
|
2014-12-11 10:37:20 -06:00
|
|
|
## Lifetime Elision
|
|
|
|
|
|
|
|
Earlier, we mentioned 'lifetime elision,' a feature of Rust which allows you to
|
|
|
|
not write lifetime annotations in certain circumstances. All references have a
|
|
|
|
lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust
|
|
|
|
will do three things to determine what those lifetimes should be.
|
|
|
|
|
|
|
|
When talking about lifetime elision, we use the term 'input lifetime' and
|
|
|
|
'output lifetime'. An 'input liftime' is a lifetime associated with a parameter
|
|
|
|
of a function, and an 'output lifetime' is a lifetime associated with the return
|
|
|
|
value of a function. For example, this function has an input lifetime:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn foo<'a>(bar: &'a str)
|
|
|
|
```
|
|
|
|
|
|
|
|
This one has an output lifetime:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn foo<'a>() -> &'a str
|
|
|
|
```
|
|
|
|
|
|
|
|
This one has a lifetime in both positions:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn foo<'a>(bar: &'a str) -> &'a str
|
|
|
|
```
|
|
|
|
|
|
|
|
Here are the three rules:
|
|
|
|
|
|
|
|
* Each elided lifetime in a function's arguments becomes a distinct lifetime
|
|
|
|
parameter.
|
|
|
|
|
|
|
|
* If there is exactly one input lifetime, elided or not, that lifetime is
|
|
|
|
assigned to all elided lifetimes in the return values of that function..
|
|
|
|
|
|
|
|
* If there are multiple input lifetimes, but one of them is `&self` or `&mut
|
|
|
|
self`, the lifetime of `self` is assigned to all elided output lifetimes.
|
|
|
|
|
|
|
|
Otherwise, it is an error to elide an output lifetime.
|
|
|
|
|
|
|
|
### Examples
|
|
|
|
|
|
|
|
Here are some examples of functions with elided lifetimes, and the version of
|
|
|
|
what the elided lifetimes are expand to:
|
|
|
|
|
|
|
|
```{rust,ignore}
|
|
|
|
fn print(s: &str); // elided
|
|
|
|
fn print<'a>(s: &'a str); // expanded
|
|
|
|
|
|
|
|
fn debug(lvl: uint, s: &str); // elided
|
|
|
|
fn debug<'a>(lvl: uint, s: &'a str); // expanded
|
|
|
|
|
|
|
|
// In the preceeding example, `lvl` doesn't need a lifetime because it's not a
|
|
|
|
// reference (`&`). Only things relating to references (such as a `struct`
|
|
|
|
// which contains a reference) need lifetimes.
|
|
|
|
|
|
|
|
fn substr(s: &str, until: uint) -> &str; // elided
|
|
|
|
fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded
|
|
|
|
|
|
|
|
fn get_str() -> &str; // ILLEGAL, no inputs
|
|
|
|
|
|
|
|
fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
|
|
|
|
|
|
|
|
fn get_mut(&mut self) -> &mut T; // elided
|
|
|
|
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
|
|
|
|
|
|
|
|
fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
|
|
|
|
fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
|
|
|
|
|
|
|
|
fn new(buf: &mut [u8]) -> BufWriter; // elided
|
|
|
|
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
|
|
|
|
```
|
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
# Related Resources
|
2012-09-15 19:09:21 -05:00
|
|
|
|
2014-11-04 01:52:36 -06:00
|
|
|
Coming Soon.
|