Реализация супертрейта по умолчанию - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть черта MyGoodTrait с функцией label(&self) -> &str. Я хочу, чтобы каждый разработчик MyGoodTrait также реализовывал Display и FromStr. Однако мне не обязательно нужны Display и FromStr, чтобы быть супертрейтами MyGoodTrait. Я бы предпочел иметь реализацию по умолчанию Display и FromStr, которая будет внутренне использовать функцию label из MyGoodTrait. Таким образом, каждый разработчик MyGoodTrait получит Display и FromStr «бесплатно», как если бы для этих черт была реализация по умолчанию.

Вот пример, аналогичный тому, что я хочу сделать, но он не компилируется:

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

Есть ли способ написать реализацию по умолчанию Display и FromStr, так что мне не нужно дублировать код для каждой структуры который реализует MyGoodTrait?

Примечание. В моем случае я использую черту, в которой serde::se::Serialize и serde::de::Deserialize являются супертрейтами. Разработчики моей черты будут использоваться в качестве ключей на карте, и я сериализую карту в JSON, поэтому мне нужно, чтобы разработчики были сериализованы в Strings. Так что это может быть примером проблемы XY

1 Ответ

1 голос
/ 09 апреля 2020

TL; DR: Вы не можете.


Вы не можете реализовать FromStr для dyn SomeTrait, потому что у него есть метод, который возвращает Result<Self, _>, следовательно, вы можете реализовать только это для типов, размер которых известен во время компиляции, что не относится к объектам черт.

Что вам действительно нужно, так это

impl<T: MyGoodTrait> FromStr for T

Но теперь вы можете нарушить правило-сироту. Как объясняет компилятор:

Реализация чужой черты возможна, только если хотя бы один из типов, для которого она реализована, является локальным. Только параметры, определенные в текущем ящике, могут быть реализованы для параметра типа.

Но вы можете сделать это, если вместо этого 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())
    }
}

Или вы может реализовать его для любого определенного c локального типа:

impl FromStr for A {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self::new())
    }
}
...