如何表示返回的关联类型实现了特征?

问题描述 投票:2回答:2

这是显示我的问题的抽象示例,从我尝试重构一些Rust代码并同时学习Rust中提取。

struct GenStruct<T> {
    field: T,
}

trait Marker {}
trait Return {}

impl Marker for i32 {}
impl Marker for u32 {}

// actually implement `Return` for GenStruct<M: Marker>,
// but compiler don't recognize that
impl Return for GenStruct<i32> {}
impl Return for GenStruct<u32> {}

struct Fake;

trait Trait<M: Marker> {
    type Ret: Return;
    fn meth(m: M) -> Self::Ret;
}

impl<M: Marker> Trait<M> for Fake {
    type Ret = GenStruct<M>;

    fn meth(m: M) -> GenStruct<M> {
        GenStruct { field: m }
    }
}

输出:

error[E0277]: the trait bound `GenStruct<M>: Return` is not satisfied
  --> src/lib.rs:23:17
   |
23 | impl<M: Marker> Trait<M> for Fake {
   |                 ^^^^^^^^ the trait `Return` is not implemented for `GenStruct<M>`
   |

编译器没有意识到我实际上为每个Return实现GenStruct<M>,其中M是Marker。为了解决这个问题,我可以这样写:

trait Marker {
    fn is_i32() -> bool;
}
trait Return {
    fn ret();
}

impl Marker for i32 {
    fn is_i32() -> bool {
        true
    }
}
impl Marker for u32 {
    fn is_i32() -> bool {
        false
    }
}

// compiler is satisfied by such implementation
impl<M: Marker> Return for GenStruct<M> {
    fn ret() {
        if M::is_i32() {
        } else {
        }
    }
}

或使用特征对象:

impl<M: Marker> Return for GenStruct<M> {}

trait Trait<'a, M: Marker + 'a> {
    fn meth(m: M) -> Box<Return + 'a>;
}

impl<'a, M: Marker + 'a> Trait<'a, M> for Fake {
    fn meth(m: M) -> Box<Return + 'a> {
        Box::new(GenStruct { field: m })
    }
}

但是,如果我使用特征对象,我不能为ReturnGenStruct<i32>编写GenStruct<u32>的专门实现。

编译器是否能够识别出我实现了GenStruct<M: Marker>或者我的代码是不是惯用的Rust?如果我的代码不是惯用的,那么编写代码的正确方法是什么?

generics rust traits
2个回答
6
投票

使用where子句,我们可以在泛型impl上添加一个额外的约束,这样它只适用于GenStruct<M>确实实现了Return

impl<M: Marker> Trait<M> for Fake
where
    GenStruct<M>: Return,
{
    type Ret = GenStruct<M>;

    fn meth(m: M) -> GenStruct<M> {
        GenStruct { field: m }
    }
}

Rust 1.33甚至通过帮助文本指示:

   = help: consider adding a `where GenStruct<M>: Return` bound

3
投票
// actually implement `Return` for GenStruct<M: Marker>,
// but compiler don't recognize that
impl Return for GenStruct<i32> {}
impl Return for GenStruct<u32> {}

为什么你认为你正在为任何Return实施GenStruct<M: Marker>?这仅针对两种特定变体实现。实现特征的类型不是封闭集;任何人都可以在将来添加特征的新实现。 Rust设计师不希望允许下游板条箱的更改影响您的箱子的编译 - 这种方式就是疯狂!

impl<M: Marker> Return for GenStruct<M> {
    fn ret() {
        if M::is_i32() { } else { }
    }
}

这是正确的说法“对于实施M的每个MarkerGenStruct<M>实现Return。无论人们如何或在何处实现这些特征并不重要,因为有保证是一个实现。

我不能写一个专门的实现

那是正确的,现在。有一个正在进行的RFC,RFC 1020: impl specialization旨在允许这些情况下的专业化。

© www.soinside.com 2019 - 2024. All rights reserved.