Declared different lifetimes or mismatched lifetimes

So, I have a pretty simple struct and method. The struct holds a vector, and the remove() method just mimics the remove() method from a hashmap. So, the user passes in a reference, a private method returns the key of that item, the item is removed, and the originally passed in item should be returned. But, I’m having a lifetimes issue.

Here is the code as it stands:

    fn remove(&mut self, token: &Token) -> Option<&Token> {
        let matched_key: Option<usize> = self.find_token_key(token.footprint());
        match matched_key {
            Some(key) => {
                &self.signatures.remove(key);
                Some(token)
            },
            None => None
        }
    }

That’s pretty simple, but panics with

error[E0623]: lifetime mismatch
–> src/data/memory/mod.rs:61:13
|
56 | fn remove(&mut self, token: &Token) -> Option<&Token> {

I expected that. So, I added the explicit lifetimes so that the passed in token and the returned token have the same annotation.

fn remove<'a>(&mut self, token: &'a Token) -> Option<&'a Token> {

That panicked with an error I didn’t expect. I’ve searched for a bit, but don’t really understand what’s happening.

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
  --> src/data/memory/mod.rs:56:1
   |
56 | fn remove<'a>(&mut self, token: &'a Token) -> Option<&'a Token> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 56:1...
  --> src/data/memory/mod.rs:56:1
   |
56 | / fn remove<'a>(&mut self, token: &'a Token) -> Option<&'a Token> {
57 | |     let matched_key: Option<usize> = self.find_token_key(token.footprint());
58 | |     match matched_key {
59 | |         Some(key) => {
...  |
64 | |     }
65 | | }
   | |_^
note: ...but the lifetime must also be valid for the anonymous lifetime #1 defined on the method body at 56:1...
  --> src/data/memory/mod.rs:56:1
   |
56 | / fn remove<'a>(&mut self, token: &'a Token) -> Option<&'a Token> {
57 | |     let matched_key: Option<usize> = self.find_token_key(token.footprint());
58 | |     match matched_key {
59 | |         Some(key) => {
...  |
64 | |     }
65 | | }
   | |_^
   = note: ...so that the method type is compatible with trait:
           expected fn(&mut data::memory::MemoryRepository, &tokens::token::Token) -> std::option::Option<&tokens::token::Token>
              found fn(&mut data::memory::MemoryRepository, &tokens::token::Token) -> std::option::Option<&tokens::token::Token>

error: aborting due to previous error

I’ve tried various combinations with no luck. What am I doing wrong?

remove() must be part of some trait, which you’ve not shown? That trait’s remove() is likely still defined as fn remove(&mut self, token: &Token) -> Option<&Token>, which means the returned Token ref is associated with self.

Interesting. The trait it implements is one that I own. And, you were right. I had updated one signature and not the other.

:blush:

Thank you.

No problem! By the way, it seems a bit odd to return a caller provided &Token back to them - any reason you don’t return a simple bool? Then you don’t need the generic lifetime parameter.

Frankly, just because I was trying to mimic the HashMap::remove() behavior.

HashMap::remove takes a key but returns the value (in an Option) - it’s different from what you’re doing here (at least from what you’ve shown).

It is different. The method that I’m using doesn’t have a true analogue. It’s also true that I’m the only one using the library, so I guess I could make it do whatever I want, lol.

I’m open to suggestions. I guess returning the Token doesn’t really make sense because they obviously already had it.

Right, and not only that, but they also had it unwrapped (i.e. without the Option). So you’re doing a bit of convolution here, where the only thing you really need is a bool to indicate if the item was removed or not (if you don’t like bool, and want something a bit more expressive, can define a custom enum with descriptive variant names - overkill for my liking, but just a suggestion).

Thanks for all your help. I’ll definately look into that.