简体   繁体   中英

Default implementation of supertrait

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM