Могу ли я условно предоставить реализацию функции черты по умолчанию? - PullRequest
2 голосов
/ 11 апреля 2019

У меня есть следующая черта:

trait MyTrait {
    type A;
    type B;

    fn foo(a: Self::A) -> Self::B;

    fn bar(&self);
}

Существуют и другие функции, такие как bar, которые всегда должны быть реализованы пользователем черты.

Я хотел бы дать foo реализацию по умолчанию, но только когда тип A = B.

Код псевдо-ржавчины:

impl??? MyTrait where Self::A = Self::B ??? {
    fn foo(a: Self::A) -> Self::B {
        a
    }
}

Это было бы возможно:

struct S1 {}

impl MyTrait for S1 {
    type A = u32;
    type B = f32;

    // `A` is different from `B`, so I have to implement `foo`
    fn foo(a: u32) -> f32 {
        a as f32
    }

    fn bar(&self) {
        println!("S1::bar");
    }
}

struct S2 {}

impl MyTrait for S2 {
    type A = u32;
    type B = u32;

    // `A` is the same as `B`, so I don't have to implement `foo`,
    // it uses the default impl

    fn bar(&self) {
        println!("S2::bar");
    }
}

Возможно ли это в Rust?

Ответы [ 3 ]

3 голосов
/ 11 апреля 2019

Вы можете предоставить реализацию по умолчанию в самом определении черты, введя избыточный параметр типа:

trait MyTrait {
    type A;
    type B;

    fn foo<T>(a: Self::A) -> Self::B
    where
        Self: MyTrait<A = T, B = T>,
    {
        a
    }
}

Эта реализация по умолчанию может быть переопределена для отдельных типов.Тем не менее, специализированные версии будут наследовать черту, связанную с определением foo() для черты, поэтому вы можете вызывать метод, только если A == B:

struct S1;

impl MyTrait for S1 {
    type A = u32;
    type B = f32;

    fn foo<T>(a: Self::A) -> Self::B {
        a as f32
    }
}

struct S2;

impl MyTrait for S2 {
    type A = u32;
    type B = u32;
}

fn main() {
    S1::foo(42);  // Fails with compiler error
    S2::foo(42);  // Works fine
}

Rust такжеимеет нестабильную функцию специализации impl , но я не думаю, что ее можно использовать для достижения того, что вы хотите.

2 голосов
/ 11 апреля 2019

Будет ли этого достаточно?:

trait MyTrait {
    type A;
    type B;

    fn foo(a: Self::A) -> Self::B;
}

trait MyTraitId {
    type AB;
}

impl<P> MyTrait for P
where
    P: MyTraitId
{
    type A = P::AB;
    type B = P::AB;

    fn foo(a: Self::A) -> Self::B {
        a
    }
}

struct S2;

impl MyTraitId for S2 {
    type AB = i32;
}

Rust Playground

Как уже отмечалось, если MyTrait столкнется с проблемами, как и другие методы, для которых MyTraitId не может обеспечить реализацию.

0 голосов
/ 12 апреля 2019

Расширение ответа user31601 и использование комментария из комментария Свена Марнаха, вот реализация черты с дополнительными функциями с использованием паттерна «методы делегата»:

trait MyTrait {
    type A;
    type B;

    fn foo(a: Self::A) -> Self::B;
    fn bar();
}

trait MyTraitId {
    type AB;
    fn bar_delegate();
}

impl<P> MyTrait for P
where
    P: MyTraitId,
{
    type A = P::AB;
    type B = P::AB;

    fn foo(a: Self::A) -> Self::B {
        a
    }
    fn bar() {
        <Self as MyTraitId>::bar_delegate();
    }
}

struct S2;

impl MyTraitId for S2 {
    type AB = i32;
    fn bar_delegate() {
        println!("bar called");
    }
}

fn main() {
    <S2 as MyTrait>::bar(); // prints "bar called"
}

Игровая площадка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...