Implementing trait method with lifetimes on a struct with lifetimes

Hello,
I'm rather new to Rust and I'm stumbling on what I think is a lifetime issue.
In playing around with the Regex crate, I tried to implement the following:

trait QuickCapture {
    fn cap<'a>(&self, i: usize) -> Option<&'a str>;
}

impl<'t> QuickCapture for regex::Captures<'t> {
    fn cap<'a>(&self, i: usize) -> Option<&'a str> {
        let got = self.get(i)?;
        Some(got.as_str())
    }
}

This gives me a rather long error saying "...the lifetime cannot outlive the lifetime 't...".
If I remove the 'a and 't lifetimes and instead use an anonymous lifetime for Captures, the code does compile, but I get an error when I go to use it.

fn parse_thing(thing_string: &str) -> Option<&str> {
    let re = Regex::new(r"thing: (.*)").unwrap();
    let caps = re.captures(thing_string)?;
    
    caps.cap(1)
}

results in the error

error[E0515]: cannot return value referencing local variable `caps`
  --> src/main.rs:18:5
   |
18 |     caps.cap(1)
   |     ----^^^^^^^
   |     |
   |     returns a value referencing data owned by the current function
   |     `caps` is borrowed here

From my understanding, re.captures takes in a &'t str and returns a Captures<'t>, and all the calls through to the as_str() in the cap() method should have the same lifetime. My assumption was that the &str returned in the Option from the cap() method should live at least as long as the &str passed into parse_thing().

Am I totally wrong here? How would I express something like this?

I've put together a little sample in the Rust Playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=accd38ce7c4dbd70626d9672d97804b9

Thanks!

It is because your QuickCapture trait requires the return value to use an unbounded lifetime 'a. Who says it has any relation to the lifetime 't, which is the lifetime that the string is actually bounded by?

trait QuickCapture<'t> {
    fn cap(&self, i: usize) -> Option<&'t str>;
}

impl<'t> QuickCapture<'t> for regex::Captures<'t> {
    fn cap(&self, i: usize) -> Option<&'t str> {
        let got = self.get(i)?;
        Some(got.as_str())
    }
}

Unbounded lifetimes are equivalent to 'a = 'static, and it didn't work because your string slice can't live for the 'static lifetime.

2 Likes

Great, thanks!
I was wondering about how to make the 't == 'a.
This makes way more sense now that I think about how an impl would return a &str. I suppose the struct would have to have some sort of lifetime on the &str it's referencing, so a trait would also need to specify that as well.

It's much simpler than I expected :slight_smile:
Thanks very much for your help!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.