I'm running into an issue where I have conflicting types, char
and AsRef<str>
:
trait Pushable<T> {
fn push(&mut self, t: T) -> &mut Self;
}
impl<T> Pushable<T> for Vec<T> {
fn push(&mut self, t: T) -> &mut Self {
self.push(t);
self
}
}
impl<T: AsRef<str>> Pushable<T> for String {
fn push(&mut self, t: T) -> &mut Self {
self.push_str(t.as_ref());
self
}
}
impl Pushable<char> for String {
fn push(&mut self, character: char) -> &mut Self {
self.push(character);
self
}
}
fn push_and_return<T, U>(mut t: T, value: U) -> T where T: Pushable<U> {
t.push(value);
t
}
I understand that rustc
is trying to future-proof my code here, but shouldn't I be able to opt-in to my own implementation?
If in the future, AsRef<str>
is implemented for char
, wouldn't the compiler still be able to overwrite the generic implementation just for char
as I would assume that String::push(&mut self, ch: char)
is faster than String::push_str(&mut self, string: &str)
even when the &str
has a length of 1?
I could just write a separate implementation for push_and_return
just for char, but I'm doing this everywhere in a file and having one function really cleans things up for me. Any possible workarounds?
Update:
I found one workaround:
trait LocalAsRef<T: ?Sized>: AsRef<T> {}
Is there a better way to handle this? It would be nice if there were a procedural-macro where I could opt out of the compiler's implementation for a specific type like this:
#[except(char)]
impl<T: AsRef<str>> Pushable<T> for String { // ...
...but I'm no language designer, so I don't know what the implications would be.