1

Rust lifetime concept is so confused for me. I have two functions below:

fn test1<'a, 'b: 'a>(x: &'a u32, y: &'b u32) -> &'a u32 {
    if x > y {
        x
    } else {
        y
    }
}

fn test2<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 {
    if x > y {
        x
    } else {
        y
    }
}

fn main() {
    let a = 5;

    {
        let b = 6;
        let c = test1(&a, &b);
        println!("{}", c);
    }

    {
        let b = 6;
        let c = test2(&a, &b);
        println!("{}", c);
    }
}

This program can be compiled and result is

6
6

However, I cannot figure out the difference between test1 and test2 Can anybody explain it?

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
mac.ma
  • 703
  • 2
  • 8
  • 22
  • 1
    Since you defined b lifetime as `'b: 'a` those functions are exactly the same. You might as well just skip the `'b` lifetime and use `'a` only. – cy3er Apr 01 '20 at 07:21
  • Does this answer your question? [Rust lifetime limitation](https://stackoverflow.com/questions/75626387/rust-lifetime-limitation) – wangliqiu Mar 04 '23 at 10:19

1 Answers1

4

TLDR: There is no practical difference.

What you have to understand is that Rust lifetime indications are not strict equality assertion, instead they denote a "longer than" relationship. So when you write:

fn foo<'a> (x: &'a i32)

You are telling the compiler that: "in order to call foo, there must exist some lifetime 'a and x must live at least as long as 'a (but x may live longer than that)".

Going back to your function definitions:

fn test1<'a, 'b: 'a>(x: &'a u32, y: &'b u32) -> &'a u32

This means:

  • There must exist some lifetime 'a such that x lives at least as long as 'a (but may live longer).
  • There must exist some lifetime 'b that is at least as long as 'a (but may be the same) such that y lives at least as long as 'b (but may live longer).
  • And the return value cannot live longer than 'a.

Since there are no other constraints on 'b, the compiler is always free to pick 'b = 'a and the code will compile as long as the constraints on 'a are satisfied.

When you call the function, the compiler searches for some lifetimes 'a and 'b that match the constraints above:

let a = 5;
{
    let b = 6;
    let c = test1(&a, &b);
    println!("{}", c);
}
  • The return value cannot live longer than 'a so 'a must start at the function call (because the return value does not exist before) and end at the closing brace at the earliest.
  • Here x is a and x must live at least as long as 'a. Since a is defined before the function call and is still alive at the closing brace, everything is fine.
  • Here y is b and y must live at least as long as 'b. If we choose 'b = 'a then everything is fine since b is defined before the function call and lives until the closing brace.

Therefore, the compiler chooses 'a == 'b starting at the function call and ending at the closing brace. Both variables a and b live longer than that but this is fine since lifetime annotations for parameters are lower bounds on the true lifetimes of the corresponding variables.

Note: the same reasoning applies to your second function and again the compiler can always pick 'b = 'a whenever all the other constraints are met.

Jmb
  • 18,893
  • 2
  • 28
  • 55
  • In my code, lifetime of a starts from "let a =5" and ends at "the last }", lifetime of b starts from "let b = 6;" and ends at "the last but one }". So how can understand " 'b: 'a " ? – mac.ma Apr 01 '20 at 08:18
  • 2
    `'a` is _not_ the lifetime of `a`. So yes, the lifetime of `a` starts at the `let a =…` line and ends at the final closing brace, but `'a` is much shorter than that. – Jmb Apr 01 '20 at 08:27