Implementing generic Borrow transitively for HashMap key lookup

45 Views Asked by At

Let's say we have a custom wrapper type MyType around a string, which I'll try generalizing later.

Borrow is implemented for it to enable looking up with a &str key in a hash map:

use std::{borrow::Borrow, collections::HashMap};

#[derive(Hash, PartialEq, Eq)]
struct MyType(String);

impl Borrow<str> for MyType {
    fn borrow(&self) -> &str {
        &self.0
    }
}

fn main() {
    let map = HashMap::from([(MyType("abc".to_string()), 3)]);
    println!("{}", map.get("abc").unwrap());
}

This works as expected: Playground

Now, let's try making MyType generic while enabling Borrow transitively:

use std::{borrow::Borrow, collections::HashMap};

#[derive(Hash, PartialEq, Eq)]
struct MyType<T>(T);

impl<T, U> Borrow<U> for MyType<T>
where
    T: Borrow<U>,
{
    fn borrow(&self) -> &U {
        &self.0
    }
}

fn main() {
    let map = HashMap::from([(MyType("abc".to_string()), 3)]);
    println!("{}", map.get("abc").unwrap());
}

This doesn't work: Playground

error[E0119]: conflicting implementations of trait `Borrow<MyType<_>>` for type `MyType<_>`
 --> src/main.rs:6:1
  |
6 | / impl<T, U> Borrow<U> for MyType<T>
7 | | where
8 | |     T: Borrow<U>,
  | |_________________^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> Borrow<T> for T
            where T: ?Sized;

For more information about this error, try `rustc --explain E0119`.
error: could not compile `playground` (bin "playground") due to 1 previous error

It conflicts with impl<T> Borrow<T> for T in the standard library.

Is it possible to make this lookup work at all in the generic case without some explicit conversion for the queried key in the callsite for lookup?

0

There are 0 best solutions below