`xxx` does not live long enough,How to fix it?

rust_playground

According to the article, change the 11th line to fn foo(b: Box<dyn for<'a> DoSomething<&'a String>>) { to solve it, but it prompts that the 17th line v does not live long enough `.

Question one:
How to fix the 13th line, // error [E0597]: temp not long enough lifespan error

Question two:
Uncomment the 20th line, can you modify the code so that it can be called twice?

This:

fn foo(b: Box<dyn DoSomething<&String>>)

Desugars to this:

fn foo<'s>(b: Box<dyn DoSomething<&'s String> + 'static>) {

Where 's is "chosen" by the caller of foo. Then you try to:

b.do_sth(&temp); // where `temp` is a local you don't return

Since the caller defines 's, they might give you an arbitrary long lifetime. You need to be able to choose an arbitrary short lifetime. So need something that implements the trait for any lifetime.

So let's fix the 's lifetime by saying:

fn foo(b: Box<dyn for<'s> DoSomething<&'s String>>) {
//                ^^^^^^^ new

Which desugars to:

fn foo(b: Box<dyn for<'s> DoSomething<&'s String> + 'static>) {

If you try this, you'll get a new error, this time at the call site on line 19. It says you're requiring the borrow of v to last for 'static (forever). That's because &'lt String can only implement the trait within the lifetime of 'lt. So 'static is too long we need to shorten that too:

fn foo<'b>(b: Box<dyn for<'s> DoSomething<&'s String> + 'b>) {

Now foo works.

If you don't need ownership, you can use &dyn Trait instead of Box<dyn Trait>.

-fn foo<'b>(b: Box<dyn for<'s> DoSomething<&'s String> + 'b>) {
+fn foo<'b>(b: &(dyn for<'s> DoSomething<&'s String> + 'b)) {
     let temp: String = "xx".to_string();
     b.do_sth(&temp)
 }
 fn main() {
     let v = "xx".to_string();
     let v = &v;
-    let x  = Box::new(v);
-    foo(x);
-    // foo(x);
+    foo(&v);
+    foo(&v);
}

And the default for the dyn Trait lifetime of applicability defaults to the lifetime of the outer reference in this case (instead of 'static like when its in a Box), so you can shorten foo's signature to:

fn foo(b: &(dyn for<'s> DoSomething<&'s String>)) {
3 Likes

I don't understand why it says "type mismatch"

fn foo<'b>(b: &(Box<dyn for<'a> DoSomething<&'a String> + 'b>)) {
    let temp: String = "xx".to_string();
    b.do_sth(&temp)
}
fn main() {
    let v = "xx".to_string();
    let v = &v;
    let x  = Box::new(v);
    foo(&x); //. error[E0308]: mismatched types
    foo(&x);
}

The compiler didn't figure out that you wanted to coerce v to a dyn ... when you were creating the Box, so it decided it must be a Box<&String>, and then hit a type mis-match later because the coercion can't apply through the Box. You can be more explicit when creating the Box:

    let x: Box<dyn for<'a> DoSomething<&'a String> + '_> = Box::new(v);

However, taking a reference to a Box is somewhat odd. Instead, you can just dereference the Box and use &dyn ... in the function, if you need the Boxes for whatever reason:

// As in my other reply
fn foo(b: &(dyn for<'s> DoSomething<&'s String> )) { ... }
fn main() {
    let v = "xx".to_string();
    let v = &v;
    let x = Box::new(v);
    foo(&*x); // <--
    foo(&*x); // <--
}

Though this is still creating a Box<&String>, the coercion can apply to the primitive references, so you'll probably still need some sort of type annotation if you need to create a Box<dyn ...> specifically. (If you had a return value or something that took the Box directly instead of behind a reference, I think the compiler would figure it out from their annotations, like in one of my previous examples.)

(I could only tell it's still creating a Box<&String> because I checked.)

1 Like

Thank you very much for your patient answers. I understand

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.