Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my reference not live long enough?

Tags:

rust

The code:

use std::fmt::Debug;

trait DoSomething<T> {
    fn do_sth(&self, value: T);
}

impl<T: Debug> DoSomething<T> for &usize {
    fn do_sth(&self, value: T) {
        println!("{:?}", value);
    }
}

fn foo(b: Box<DoSomething<&i32>>) {
    let s = 123;
    b.do_sth(&s);
}

fn main() {
    foo(Box::new(&3));
}

The compiler error message is:

error[E0597]: `s` does not live long enough
  --> src/main.rs:15:14
   |
13 | fn foo(b: Box<DoSomething<&i32>>) {
   |        - has type `std::boxed::Box<(dyn DoSomething<&'1 i32> + '_)>`
14 |     let s = 123;
15 |     b.do_sth(&s);
   |     ---------^^-
   |     |        |
   |     |        borrowed value does not live long enough
   |     argument requires that `s` is borrowed for `'1`
16 | }
   | - `s` dropped here while still borrowed

I think this &s is just used in foo, the foo method ends and doesn't borrow anymore? But that's not the case. Who's still borrowing it? How to solve this problem?

like image 365
iDuanYingJie Avatar asked Apr 26 '26 23:04

iDuanYingJie


1 Answers

Whenever there's a reference in Rust, there's a lifetime. In most cases, the compiler can infer it, so that you don't have to write it down, but it's still there. When you get confusing lifetime errors, it helps to try to figure out what these implicit lifetimes are.

fn foo(b: Box<DoSomething<&i32>>) {
    let s = 123;
    b.do_sth(&s);
}

This is equivalent to

fn foo<'y>(b: Box<DoSomething<&'y i32>>) {
    let s = 123;
    b.do_sth(&s);
}

In other words, the lifetime of the reference passed to do_sth is actually "whatever the caller of foo wants". This function signature allows me to write this main:

fn main() {
    let b : Box<DoSomething<&'static i32>> = Box::new(&3);
    foo(b);
}

And if you expand the DoSomething trait for this parameter, you end up with this function:

fn do_sth(&self, value: &'static i32) {
    println!("{:?}", value);
}

which foo is trying to call with a reference to a local variable.

I hope that explains why your code doesn't work.

As for what you should write instead, I think that's not really answerable in general. There's no way to write the do_sth signature in a way that says "all references passed to this function may be transient". You'll have to look at your real code and think of a better way of writing it.

like image 51
Sebastian Redl Avatar answered Apr 30 '26 03:04

Sebastian Redl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!