Lifetime may not live long enough error

I am getting the following error but can't work out how to fix it. The Application's lifetime 'a is longer than anything it contains since self.config, self.dpl, etc. is all contained in the Application struct.

error: lifetime may not live long enough
   --> ...\src\
12  |   impl<'a> Application<'a> {
    |        -- lifetime `'a` defined here
76  |       pub(crate) fn load(&mut self, which: Which, filename: &Path) {
    |                          - let's call the lifetime of this reference `'1`
105 |                       match self.dpl.dapdf_open_read_only(
    |  ___________________________^
106 | |                         &self.config.query.filename2,
107 | |                         &self.config.query.password2,
108 | |                     ) {
    | |_____________________^ argument requires that `'1` must outlive `'a`

Can anyone help?

It would probably help if you have us the types of the struct fields involved as well as signatures of the methods called here, in particular for dpl and dapdf_open_read_only.


I think all I really need is some syntax to say that given this:

pub struct Application<'a> {
    pub dpl: Dpl<'a>,
    pub dapdf1: Option<DaPdf<'a>>,

That the life of Application >= the life of Dpl which is >= the life of DaPdf.

Are you trying to construct a value of type Application where the dapdf1 field borrows from the dbl field? This will never work (the "self-referential struct" problem) -- you have to store the borrowing DaPdf separately from the borrowed Dpl.

In main:

fn main() {
    match Dpl::new() {
        Ok(dpl) => {
            let mut app = Application::new(dpl);
        Err(err) => ui_util::popup_error(&err.to_string()),

I then use the dpl throughout. The only way to get a DaPdf is by calling a dpl method.

How can I store the DaPdf separately: and more the to point why should I? At application start up I create a Dpl and store that for use in a new Application. Then during runtime I want to create and sometimes replace DaPdfs.

I see a Dpl::new() function call which indicates to me that the lifetime in Dpl<'a> might not actually be borrowing from anything else, and thus either it’s unwanted, or it’s meant for other use-cases than the code you showed us (and there’s additional API that would introduce how the borrows / lifetime becomes relevant in the first place), or Dpl is trying to be a self-referential type itself.

As mentioned previously, you need to provide more type signatures for people to actually understand what kind of code you have. Or maybe just present the whole code somewhere if that’s possible and if seems unclear to you what struct definitions and function signatures would be relevant for understanding the code in question and for exploring the possibilities of alternative approaches.

In particular, I’m still interested in the function signature of dapdf_open_read_only, like I already mentioned. I have a hunch that it might feature some kind of &'a self / &'a mut self parameter, or it might expect &'a … references as its argument, or something like that. These lifetime restrictions from the function signature then would either be unnecessary and can be improved, or they might be necessary because you’re storing some of these references in the struct itself, in which case you’d be attempting to store a reference (in)to one field in a different field of the same struct.

If the question is how to split up the data structure into multiple parts to avoid the self-borrowing-ness, all such instances of borrowing that’s currently happening within the same struct need to be identified, and then you could try to find two or more parts so that references in one part of the struct only borrows from previous parts. E.g. here it looks like something in self.dpl might borrow from something in self.config in the Application, so those two parts might need to live in separate parts.

To minimize the API changes in such a refactor, it’s still possible to have the structs mostly “bundled up” into one thing anyways, by storing a reference to the first part as a field in the second part (assuming exactly 2 parts). This is all fairly abstract and could be unactionable if my assumptions are wrong or the explanations are to hard to understand; working with a concrete full code example giving code examples for the approach would probably be more straightforward.

1 Like

You're right that Dpl is an API from another project. It stores one i32, plus a whole bunch of libloading::Symbols (i.e., function refs to a shared lib'y) and the 'a lifetime is purely for those.

The signature is here (self is a DaPdf with a 'a lifetime):

    pub(crate) fn open_file_read_only(
        &mut self,
        filename: &str,
        password: &str,
    ) -> Result<()> {

A DaPdf stores one String, a few i32s and again a bunch of libloading::Symbols.

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.