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?