How to borrow to a tuple

Hi all,

Given this struct:

struct Name {
    name: String,
    version: u8,
}

I want to be able to borrow it into a &(&str, u8). Trying to implement this:

impl Borrow<(&str, u8)> for Name {
    fn borrow(&self) -> &(&str, u8) {
        &(&self.name, self.version)
    }
}

Gives this error:

error: `impl` item signature doesn't match `trait` item signature
   --> src/lib.rs:9:5
    |
9   |     fn borrow(&self) -> &(&str, u8) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Name) -> &(&str, u8)
    |
    = note: expected `fn(&Name) -> &(&str, u8)`
               found `fn(&Name) -> &(&str, u8)`

One thing I'm confused about is the "expected" versus "found" sections, since they are visually identical. I think they actually differ in lifetimes, but rust has [not so] helpfully elided them from the diagnostic.

Does anyone have any hints about how to implement this trait?

Playground link

1 Like

You can't. As you have noted, there is a difference in lifetimes,

This

impl Borrow<(&str, u8)> for Name {
    fn borrow(&self) -> &(&str, u8) {
        // creates a temporary, and tries to return a reference to it
        &(&self.name, self.version)
    }
}

Unless you type explicitly contains (&str, u8), you cannot borrow as (&str, u8).

1 Like

Bummer! But thanks for the prompt answer!

Here's a quick follow up:

If I have a HashMap<Name, _>, and I want to look up entries with .get() -- is there anyway to do that by passing in something like a (&str, u8) (that is, I don't want to construct the Name just to see if it exists in the map).

Ah, that's tricky. I don't think that you can. One way around this would be to change Name to

struct Name<'a> {
    name: Cow<'a, String>,
    version: u8,
}

Then store Name<'static> in the HashMap. This has the downside of increased memory usage, and you can avoid that with some specialized crates like beef.

You can then access the HashMap using

Name {
    name: Cow::Borrowed(name),
    version
}

However this is a lot of boilerplate to get rid of that allocation. I think there may be a better way, but I can't think of it right now. (This solution is untested, so take it with a grain of salt)

1 Like

There's a neat trick you can apply here, described in a StackOverflow post. It's not zero-cost, but it does not increase the storage space required by the hashmap and it does not require changing the definition of Name.

4 Likes

That's clever, thanks!

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