Try to explain via de-sugraing, as is the style of the nomicon.

pull/4/head
Edd Barrett 8 years ago
parent 005053e382
commit 87b4ca44fa

@ -226,13 +226,11 @@ Consider the following program:
```rust,ignore ```rust,ignore
fn main() { fn main() {
let s1 = String::from("short"); let s1 = String::from("short");
{
let s2 = String::from("a long long long string"); let s2 = String::from("a long long long string");
println!("{}", shortest(&s1, &s2)); println!("{}", shortest(&s1, &s2));
}
} }
fn shortest<'a>(x: &'a str, y: &'a str) -> &'a str { fn shortest<'k>(x: &'k str, y: &'k str) -> &'k str {
if x.len() < y.len() { if x.len() < y.len() {
return x; return x;
} else { } else {
@ -243,30 +241,60 @@ fn shortest<'a>(x: &'a str, y: &'a str) -> &'a str {
The idea is that `shortest()` returns a reference to the shorter of the two The idea is that `shortest()` returns a reference to the shorter of the two
strings referenced by its arguments, but *without* allocating a new string. strings referenced by its arguments, but *without* allocating a new string.
Let's de-sugar main so we can see the implicit lifetimes:
```rust,ignore
fn main() {
'a {
let s1 = String::from("short");
'b {
let s2 = String::from("a long long long string");
'c {
// Like before, an anonymous scope introduced since &s1 doesn't
// need to last as long as s1 itself, and similarly for s2.
println!("{}", shortest(&'b s1, &'a s2));
}
}
}
}
```
The two references passed at the call-site of `shortest()` have different lifetimes Now we see that the references passed as arguments to `shortest()`, i.e. `&s1`
since their referents are defined in different scopes. The and `&s2`, actually have different lifetimes, `&'a` and `&'b`, since their
string reference `&s1` is valid longer than the string reference `&s2`, yet the signature referents are defined in different scopes. However, the signature of
of `shortest()` requires that these two references have the same lifetime. `shortest()` requires that these two references (and also the returned
Furthermore, the returned string reference must also share this same lifetime too. reference, which has lifetime `'c`) have the same lifetime. So how does the
So how does the compiler make sure this is the case? compiler make sure this is the case?
At the call-site of `shortest()`, the compiler must try to *convert* the lifetimes of At the call-site of `shortest()`, the compiler must try to *convert* the lifetimes of
the references marked `&'a` in the `shortest()` function signature the references marked `&'a` in the signature of `shortest()`
into a single *unified* lifetime. This new lifetime must be shorter than, or equally as into a single compatible lifetime. This new lifetime must be shorter than, or equally as
long as, each of the reference lifetimes in isolation. A reference `&'o T` can be long as, all three of the original reference lifetimes involved. Therefore a reference `&'o` can be
converted to to `&'p T` if (and only if) it can be proven that `'o` lives as converted to to `&'p` if `'o` lives at least as long as `'p`.
long as (or longer than) `'p`. In our example the references `'&s1`, `&s2` and
the returned reference can all be shown to be valid for the In our example:
scope created by the `let s2` binding (see above for information on implicit
scopes introduced by `let` bindings). So in this case, we can prove that the * `&'b` outlives `'c`, so `&'b` can be converted to `&'c`.
lifetimes can be unified, and as a * `&'a` outlives `'c`, so `&'a` can be converted to `&'c`.
result he compiler accepts the program. * The returned reference has lifetime `&'c` already.
If, on the other hand, the compiler cannot find such a lifetime, then the So these references are unified in `&'c`, therefore the lifetime constraints
lifetime constraints described by the program are inconsistent, and the imposed by `shortest()` are consistent, and the compiler accepts the program.
compiler will reject the program. For example:
Now consider a slight variation on `main()` like this:
```rust,ignore ```rust,ignore
XXX fn main() {
let a = String::from("short");
{
let c: &str;
let b = String::from("a long long long string");
c = min(&a, &b);
}
}
``` ```
XXX Desugar.
XXX Explain why it doesn't work.

Loading…
Cancel
Save