Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If the return value of a function has the same lifetime as one of the arguments, then the return value is considered a borrow of the argument?

Where in Rust's specification does it say that if the returned reference of a function has the same lifetime as one of the reference arguments, then the returned reference is considered a borrow of that argument?

Example:

struct T {
    i: i32
}
struct U {
    i: i32
}
static GLOBAL: U = U { i: 0 };
fn foo<'t, 'u>(t: &'t mut T, u: &'u mut U) -> &'u U {
    &GLOBAL
}
fn main() {
    let mut t = T { i: 0 };
    let mut u = U { i: 0 };
    let ref_u = foo(&mut t, &mut u);
    let ref_u_2 = &u;
    // println!("{}", ref_u.i);
}

(Playground)

If I uncomment the println!, the compilation will fail with the message:

error[E0502]: cannot borrow `u` as immutable because it is also borrowed as mutable
  --> src/main.rs:15:19
   |
14 |     let ref_u = foo(&mut t, &mut u);
   |                             ------ mutable borrow occurs here
15 |     let ref_u_2 = &u;
   |                   ^^ immutable borrow occurs here
16 |     println!("{}", ref_u.i);
   |                    ------- mutable borrow later used here

I think the reason why I have to use println! at the end to make the compilation fail is because of non-lexical lifetimes. I need to use ref_u so that its lifetime doesn't end immediately. I used two arguments to show that the t argument is unaffected, but this example also works with only one argument.

Note that the returned reference has the 'static lifetime. To me, this implies the following two points:

  1. The borrow checker never recursively checks the body of the functions you call. It only looks at the function signature. If it does, then it would have seen that the returned reference can actually outlive the u argument.
  2. If the returned reference of a function has the same lifetime as one of the reference arguments, then the returned reference is considered a borrow of that argument. This is proven by the fact that if you change the return type to &'t U, then the program compiles.

This seems reasonable, but I couldn't find any explicit reference to this rule in the Rust Reference or the Rust Book. Is this behavior implied somewhere?

Also, I find it interesting that the error message considers ref_u a mutable borrow, even though it isn't a mutable reference.

like image 379
palapapa Avatar asked Sep 01 '25 04:09

palapapa


1 Answers

This is in the book under Lifetime Annotations in Function Signatures:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
[…]

function definition specifying that all the references in the signature must have the same lifetime 'a

So no I would not say the return value borrows from the parameter, instead I'd say it has the same lifetime. It certainly can borrow from the parameter, but it does not have to. That means as long as the return value is considered live, the parameter is also considered live.

like image 122
cafce25 Avatar answered Sep 02 '25 17:09

cafce25