The associated type may not live long enough

Hello, so I am quite new to Rust, and I just run into this issue relating to a value may not live long enough. I tried to search for similar questions, but none of them is similar "enough" for me to know what should be done.

I am trying to write a simple program that draw graphs, using plotter.

use plotters::prelude::*;

pub fn gen_ven<T: plotters::drawing::IntoDrawingArea>(backend: T) -> Result<(), Box<dyn std::error::Error>> {
    let root = backend.into_drawing_area();
    root.fill(&WHITE)?;
    root.present().unwrap();
    Ok(())
}

Look simple enough, but upon compiling, I got

error[E0310]: the associated type `<T as plotters::prelude::DrawingBackend>::ErrorType` may not live long enough
 --> src\ven.rs:6:5
  |
6 |     root.fill(&WHITE)?;
  |     ^^^^^^^^^^^^^^^^^^
  |
  = help: consider adding an explicit lifetime bound `<T as plotters::prelude::DrawingBackend>::ErrorType: 'static`...
  = note: ...so that the type `<T as plotters::prelude::DrawingBackend>::ErrorType` will meet its required lifetime bounds

So I presume this error occurs because the error inferred from the fill trait does not "live long enough" or something, as when I do un_wrap , i.e root.fill(&WHITE).unwrap();, then everthing worked fine.

However, for this random function, the code compiled:

fn find_char_index_in_first_word(text: &str, char: &char) -> Result<usize, Box<dyn std::error::Error>> {
    let first_word =  match text.split(" ").next().is_some() == true {
        true => text.split(" ").next().ok_or("error happen")?,
        false => return Ok(0)
    };

    let res = first_word.find(|x| &x == char);
    match res {
        Some(x) => Ok(x),
        None    =>  Ok(0),
    }
}

The ? worked, which I presume it's what the ? should be doing.
So what happened in my first case?
Thank you.

The difference is that in your "random function", the error type isn't generic. It's &str. And there's an impl in the standard library for converting any &str (even non-'static!) into Box<dyn Error> (which is really just shorthand for Box<dyn Error + 'static>).

Internally, that's possible because a string 1. is copiable and 2. makes a fine error message, so you can create an owned Box<dyn Error + 'static> by actively copying the error message into a heap-allocated, owned String and using it to create a different, owned type implementing Error using that message. And that's exactly what std's impl From<&'_ str> for Box<dyn Error + 'static> does. So the error trait object isn't really created from your (borrowed) string; it's created from a different, private, owning type that contains an owned copy of your string.

In contrast, your generic drawing function only requires a dumb trait object coercion, meaning that you can create a Box<dyn Error> from your <T as DrawingBackend>::ErrorType only if/because there is an ErrorType: Error bound on that associated type. However, this means that there's no copying-into-an-owned-type trickery possibly going on; the trait object is created directly from your error, by means of a regular, language built-in coercion inserted directly by the compiler. Now this means that if you want to create a Box<dyn Error + 'static> from it, you have to constrain it to be 'static itself.

1 Like

So what do you suggest I fix with my code, so that I can use the ? instead of pure unwrap? Because my solution is not that elegant:

match root.fill(&WHITE) {
        Err(err) => {
            return Err(err.to_string())?
        },
        _ => {}
    }

Thank you

As I pointed out in my last sentence, the simplest solution is to add a 'static bound on the error type.