Inserting HashSet in Self Requires Lifetime Parameter

I have a struct as below:

/// A shell for the game.
struct Shell<'a> {
    codes: HashSet<Code<'a>>,
    buffer: Vec<char>,
}

And has its impl:

impl<'a> Shell<'a> {
    fn new() -> Self {
        Shell {
            codes: HashSet::new(),
            buffer: vec![],
        }
    }

    fn add_code(&mut self, name: &str, invokable: Box<dyn Invokable>) -> ShellResult<()> {
        if self.codes.iter().any(|c| c.name == name) {
            Err(ShellError::AlreadyExists {
                name: String::from(name),
            })
        } else {
            let code_r = Code::new(name, invokable, &self);  // HERE IS THE PROBLEM
            match code_r {
                Ok(c) => {
                    self.codes.insert(c);
                    Ok(())
                }
                Err(e) => Err(e),
            }
        }
    }
}

The problem is in add_code method. Code::new in code_r fails saying:

cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements

note: expected  `Code<'a>`
         found  `Code<'_>`rustc(E0495)

Code struct also has that lifetime 'a. Check it out:

#[derive(Derivative)]
#[derivative(Hash, PartialEq, Eq)]
/// Code is a single cheat command.
struct Code<'a> {
    name: String,
    #[derivative(Hash = "ignore", PartialEq = "ignore")]
    invokable: Box<dyn Invokable>,
    #[derivative(Hash = "ignore", PartialEq = "ignore")]
    shell: &'a Shell<'a>,
}

Note: Uses derivative crate.

I can kinda understand where it's coming from. code_r is going to drop after add_code scope so it's complaining about that but I do not know how to solve it. How do I make code_r live longer, in scope of struct to be exact?


Environment

  • Rust 1.43.1

The problem here is that you are trying to make a self-referential value. Shell refers to Code, which in turn refers to the original Shell. This means that Code and Shell must outlive each other, which is not possible. Is it possible to remove the shell field from Code and instead pass a shell argument to all methods on Code that require it?

1 Like

It is not possible to make a struct where one field references another.

1 Like

Ah okay, now I see it. I need to redesign it.

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.