I have a trait, MyGoodTrait
, with the function label(&self) -> &str
. I want every implementor of MyGoodTrait
to also implement Display
and FromStr
. However, I do not necessarily need Display
and FromStr
to be supertraits of MyGoodTrait
. I would rather somehow have a default implementation of Display
and FromStr
, which will internally use the label
function from MyGoodTrait
. That way, every implementor of MyGoodTrait
will get Display
and FromStr
"for free", as if there was a default implementation for those traits.
Here is an example that is similar to what I want to do, but it does not compile:
use std::str::FromStr;
pub trait MyGoodTrait {
fn new() -> Self;
fn label(&self) -> &'static str;
}
impl FromStr for dyn MyGoodTrait {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::new())
}
}
pub struct A {}
impl MyGoodTrait for A {
fn new() -> Self {
A{}
}
fn label(&self) -> &'static str {
"A"
}
}
pub struct B {}
impl MyGoodTrait for B {
fn new() -> Self {
B{}
}
fn label(&self) -> &'static str {
"B"
}
}
// In this hypothetical, A and B now both have `fmt` and `from_str` functions
Is there a way to write this default implementation of Display
and FromStr
, such that I do not have to duplicate the code for each struct that implements MyGoodTrait
?
Note: My actual use case is that I have a trait which has serde::se::Serialize
and serde::de::Deserialize
as supertraits. The implementors of my trait will be used as keys in a map, and I will serialize the map to JSON, so I need the implementors to be serialized to Strings. So this may be an example of the XY Problem
TL;DR: You can't.
You can't implement FromStr
for dyn SomeTrait
because it has a method that returns a Result<Self, _>
, hence you can only implement it for types whose size are know at compile time, which is not the case of trait objects.
What you would really want is
impl<T: MyGoodTrait> FromStr for T
But now you might violate the orphan rule. As the compiler explains:
Implementing a foreign trait is only possible if at least one of the types for which is it implemented is local. Only traits defined in the current crate can be implemented for a type parameter.
But you could do it if FromStr
was a local trait instead:
/// Copy of `std::str::FromStr`
trait Foo: Sized {
type Err;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
impl<T: MyGoodTrait> Foo for T {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::new())
}
}
Or you could implement it for any specific local type:
impl FromStr for A {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::new())
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.