Skip to content

Add lifetime elision information to the ownership guide. #19736

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
Jan 6, 2015
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
79 changes: 77 additions & 2 deletions src/doc/guide-ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@ fn add_one(num: &int) -> int {
```

Rust has a feature called 'lifetime elision,' which allows you to not write
lifetime annotations in certain circumstances. This is one of them. Without
eliding the lifetimes, `add_one` looks like this:
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:

```rust
fn add_one<'a>(num: &'a int) -> int {
Expand Down Expand Up @@ -449,6 +450,80 @@ 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>`.

## 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
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a comment here is warranted similar to this. If you don't recognize this, it is puzzling why int doesn't get a lifetime too.

// `lvl` doesn't need a lifetime because it's not a reference (`&`). Only references need lifetimes.

Copy link
Member Author

Choose a reason for hiding this comment

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

added

Copy link
Member

Choose a reason for hiding this comment

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

It's not only references: struct Foo<'a> { ... } would be fn foo<'a>(x: Foo<'a>).

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed


// 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
```

# Related Resources

Coming Soon.