supertrait 的默认实现

Its*_*mmy 5 traits rust

我有一个特征 ,MyGoodTrait具有函数label(&self) -> &str。我希望 的每个实现者MyGoodTrait也实现DisplayFromStr。然而,我并不一定需要DisplayFromStr成为 的超特质MyGoodTrait。我宁愿以某种方式拥有Displayand的默认实现FromStr,它将在内部使用label来自 的函数MyGoodTrait。这样,每个实现者都MyGoodTrait将“免费”获得DisplayFromStr就好像这些特征有一个默认实现一样。

这是一个与我想要做的类似的示例,但它无法编译:

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
Run Code Online (Sandbox Code Playgroud)

有没有办法编写Displayand的默认实现FromStr,这样我就不必为实现的每个结构重复代码MyGoodTrait

注意:我的实际用例是我有一个具有serde::se::Serializeserde::de::Deserialize作为超级特征的特征。我的特征的实现者将用作映射中的键,并且我会将映射序列化为 JSON,因此我需要将实现者序列化为字符串。所以这可能是XY 问题的一个例子

mca*_*ton 3

TL;DR:你不能。


您无法实现FromStrfordyn SomeTrait因为它有一个返回 a 的方法Result<Self, _>,因此您只能为在编译时知道大小的类型实现它,而特征对象则不是这种情况。

你真正想要的是

impl<T: MyGoodTrait> FromStr for T
Run Code Online (Sandbox Code Playgroud)

但现在你可能违反了孤儿规则。正如编译器所解释的:

仅当所实现的至少一种类型是本地类型时,才可能实现外来特征。类型参数只能实现当前包中定义的特征。

FromStr但如果是本地特征,你也可以这样做:

/// 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())
    }
}
Run Code Online (Sandbox Code Playgroud)

或者您可以为任何特定的本地类型实现它:

impl FromStr for A {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self::new())
    }
}
Run Code Online (Sandbox Code Playgroud)