Skip to content

HashMap struct key with 'static lifetime screws with return lifetime using methods like .get() #124614

Open
@jsdw

Description

@jsdw

I'm not sure what words to use to actually describe (or search for a dupe) this issue, so I'll just post it here and hope that it makes more sense to you guys (and sorry if it is a dupe; I'm almost sure it would be)!

So basically, if I write this code:

use std::collections::HashMap;

#[derive(PartialEq,Eq,Hash)]
struct Key<'a> {
    key: &'a str
}

struct Foo {
    types: HashMap<Key<'static>, String>,
}

impl Foo {
    fn resolve<'this, 'a>(
        &'this self,
        key: &'a str,
    ) -> Option<&'this String> {
        self.types.get(&Key { key })
    }
}

I get back this error:

error: lifetime may not live long enough
  --> src/lib.rs:17:9
   |
13 |     fn resolve<'this, 'a>(
   |                -----  -- lifetime `'a` defined here
   |                |
   |                lifetime `'this` defined here
...
17 |         self.types.get(&Key { key })
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'this` but it is returning data with lifetime `'a`
   |
   = help: consider adding the following bound: `'a: 'this`

Despite the fact that HashMap::get() returns the values with a lifetime of self, and nothing to do with the key provided.

However, this does work:

use std::collections::HashMap;

#[derive(PartialEq,Eq,Hash)]
struct Key<'a> {
    key: &'a str
}

struct Foo {
    types: HashMap<&'static str, String>,
}

impl Foo {
    fn resolve<'this, 'a>(
        &'this self,
        key: &'a str,
    ) -> Option<&'this String> {
        self.types.get(key)
    }
}

Removing the struct indirection when defining the key type seems to make things happy!

Background

The above is a minimal reproduction of the issue I ran into, but the reason I ran into it is because I want to have something like:

use std::collections::HashMap;

struct Foo {
    types: HashMap<(String,String), String>,
}

impl Foo {
    fn resolve<'this, 'a>(
        &'this self,
        key1: &'a str,
        key2: &'a str,
    ) -> Option<&'this String> {
        self.types.get(&(key1, key2))
    }
}

In other words, I want to be able to borrow more than 1 value to lookup some owned key in the hashmap. I went down the route of trying struct Key<'a> { a: Cow<'a,str>, b: Cow<'a,str> and then HashMap<Key<'static>, String>, but this led me to bumping up against this odd lifetime issue :)

Any pointers would be amazingly welcome!

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-collectionsArea: `std::collections`A-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions