Question abt RUST lifetime

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.

Quote from rust doc above. Say a function with two auguments and none of them relate to &self or &mut self. then what the output lifetime should be?

depending on the return in the function body?

It depends.
If you don’t have any other borrowed argument, you only can return the ownership of that value. For example:

fn add(param1:u32, param2:u32 ) - > u32 {
return param1 + param2;
}

But you can’t return a &u32 (There’s no way to know the lifetime)

But, if there’s at least one borrowed, you can return the value with a lifetime (elided or not):

fn test(param1:&u32, param2:u32) -> &u32 { … }
In this case, the lifetime of the value returned is the same as param1’s lifetime.

Or:

fn test(param1:&u32, param2:u32) -> u32 { … }
In this case, there’s no lifetime, you’re returning the ownership.

If there’s more than one borrowed, you must specify explicitly the lifetime.

fn test<'a,'b>(param1:&'a u32, param2:&'b u32) -> &'a u32 { … }

2 Likes

Thank you very much. This is what I was confused before.

1 Like

@Leon I don’t know what your rust level is, but I myself maintain the following rule:

where-ever possible respect the rustc compilers’ guidance on lifetime of your objects. This means: avoid specifying a lifetime (sometimes you find it is necessary, but then that might indicate you’d want to re-organise your module a bit).

Thanks for your sharing. I am a starter. Do you mean eventually we can find an implicit way?

I mean that you don’t have to think too much about lifetime of your objects. Let the rust compiler do it for you.

It is sufficient to observe that if you borrow an object, it needs to live longer than the borrow. However obvious that may be, it is sufficient to understand lifetime.

1 Like

Got it. The borrow checker is really powerful. :smile:

2 Likes

one more interesting thing. see below code.

struct Point { x: i32, y: i32 }
struct Q{m1 : Point, m2 :Point}
fn main() {
let q : Q = Q{m1 : Point{x: 1,y: 2}, m2 : Point{x:3,y:4}};
let Q{m1:ref p1, m2: p2} = q; // compiler say cant bind by-ref and by-move in same pattern

but I do can archive the target which make one element by-ref and another one by-move with below words:

let Q{m1:ref p1, m2:_}=q;
let p2=q.m2;

now p1 is by-ref and p2 is by-move, you cant not use q.m2 anymore.

a little dizzy here. anybody know why? any potential risk in this let Q{m1:ref p1, m2: p2} = q; ?

From the docs https://doc.rust-lang.org/error-index.html#E0009 :

In a pattern, all values that don’t implement the Copy trait have to be bound the same way. The goal here is to avoid binding simultaneously by-move and by-ref.
This limitation may be removed in a future version of Rust.

Then, you can do:

#[derive(Clone, Copy)]
struct Point { x: i32, y: i32 }
#[derive(Clone, Copy)]
struct Q{m1 : Point, m2 :Point}
2 Likes

Thank you!!! :smiley: