Search code examples
rustlifetimetrait-objects

Shared &str along multiple structs conflicts with Lifetimes


I have the following code:

pub trait Regex: RegexClone {
    fn check(&self) -> Result<u32,(/* errors should detail where it fails*/)>;
    fn next(&self) -> Option<Box<dyn Regex>>;
}

pub trait RegexClone {
    fn regex_clone(&self) -> Box<dyn Regex>;
}
    
pub struct PatternAnyCharacter<'a>{
    string: &'a str
}
    
impl RegexClone for PatternAnyCharacter<'_> {
    fn regex_clone(&self) -> Box<dyn Regex> {
        return Box::new(PatternAnyCharacter {string: self.string})
    }
}

impl Regex for PatternAnyCharacter<'_> {
    fn check(&self) -> Result<u32, ()> {
        if self.string.len() > 0 {
            return Ok(1);
        }
        Err(())
    }

    fn next(&self) ->  Option<Box<dyn Regex>> {
        None
    }
}

The idea is that when i call regex_clone i get a new Box<dyn Regex> with the same &str as member, i supossed that since im only using inmutable references when calling regex_clone it would give me a new struct with the same string slice, since is a reference im not moving anything, however the compiler complains the following:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/lib.rs:63:25
   |
63 |         return Box::new(PatternAnyCharacter {string: self.string})
   |                         ^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
  --> src/lib.rs:61:41
   |
61 | impl RegexClone for PatternAnyCharacter<'_> {
   |                                         ^^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:63:54
   |
63 |         return Box::new(PatternAnyCharacter {string: self.string})
   |                                                      ^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
  --> src/lib.rs:63:16
   |
63 |         return Box::new(PatternAnyCharacter {string: self.string})
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected `Box<(dyn Regex + 'static)>`
              found `Box<dyn Regex>`

How can i solve this so i can share the same string slice with multiple struct? i thought about foregoing the string slice as member entirely and passing it as parameter to check, but hopefully i can avoid it.


Solution

  • You need to define at the trait that the returned dyn Regex can't outlive &self if you want to allow it to borrow from parts of &self.:

    pub trait RegexClone {
        fn regex_clone<'a>(&'a self) -> Box<dyn Regex + 'a>;
    } 
    

    (You can also use an anonymous lifetime (Box<dyn Regex + '_>), but this is easier to understand.)

    Side note: I don't think "clone" is the right name for such a function.