【问题标题】:Implementing trait with method returning generic trait使用返回通用特征的方法实现特征
【发布时间】:2017-02-28 01:53:17
【问题描述】:

我正在尝试设计一对特征(例如线性代数中的RowVectorColumnVector),其中每个特征从其方法之一返回另一个特征(例如transpose)。我希望将来能够添加任一特征的实现(例如密集和稀疏向量实现)。

#[macro_use]
extern crate derive_new;

trait RowVector<Element> {
    fn transpose(self) -> ColumnVector<Element>;
}

trait ColumnVector<Element> {
    fn transpose(self) -> RowVector<Element>;
}

#[derive(new, Debug)]
struct VecRowVector<Element> {
    vec: Vec<Element>
}

#[derive(new, Debug)]
struct VecColumnVector<Element> {
    vec: Vec<Element>
}

impl<Element> RowVector<Element> for VecRowVector<Element> {
    fn transpose(self) -> VecColumnVector<Element> {
        VecColumnVector::new(self.vec)
    }
}

impl<Element> ColumnVector<Element> for VecColumnVector<Element> {
    fn transpose(self) -> VecRowVector<Element> {
        VecRowVector::new(self.vec)
    }
}

fn main() {
    let row_vector = VecRowVector::new(vec![1,2,3]);
    let col_vector = VecColumnVector::new(vec![1,2,3]);
    println!("{:?}", row_vector.transpose());
    println!("{:?}", col_vector.transpose());
}

我收到一条错误消息,指出 VecColumnVector 不是 ColumnVector,它需要 'static 值。

error[E0053]: method `transpose` has an incompatible type for trait
  --> src\main.rs:22:31
   |
4  |         fn transpose(self) -> ColumnVector<Element>;
   |                               --------------------- type in trait
...
22 |         fn transpose(self) -> VecColumnVector<Element> {
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^ expected trait ColumnVector, found struct `VecColumnVector`
   |
   = note: expected type `fn(VecRowVector<Element>) -> ColumnVector<Element> + 'static`
   = note:    found type `fn(VecRowVector<Element>) -> VecColumnVector<Element>`

我不是让VecColumnVector 成为ColumnVector 的子类型吗?或者我是否需要以某种方式告诉特征它不需要是 static 生命周期?

【问题讨论】:

    标签: generics rust traits


    【解决方案1】:

    你正试图返回一个特征。虽然使用trait object 可以做到这一点,但这可能不是您想要做的。更好的设计是引入 Transpose 特征,您可以使用与 Rust 内置的 FromInto 转换特征类似的方式对其进行建模。

    trait Transpose<To> {
        fn transpose(self) -> To;
    }
    
    impl<Element> Transpose<VecColumnVector<Element>> for VecRowVector<Element> {
        fn transpose(self) -> VecColumnVector<Element> {
            VecColumnVector::new(self.vec)
        }
    }
    
    impl<Element> Transpose<VecRowVector<Element>> for VecColumnVector<Element> {
        fn transpose(self) -> VecRowVector<Element> {
            VecRowVector::new(self.vec)
        }
    }
    

    【讨论】:

    • 如何更新 RowVectorColumnVector 特征以指示实现它们的每个结构也必须实现相应的 Transpose
    • 我认为这会变得相当复杂:每个特征的约束之间都会有循环引用,因为您必须严格成对定义 impl,这在 Rust 中很难表达。一个更简单(也更灵活)的设计是不对类型本身施加任何约束,而是对使用类型的地方施加约束。
    • 所以我不能编写像f&lt;Element&gt;(r: &amp;RowVector&lt;Element&gt;, c: &amp;ColumnVector&lt;Element&gt;) 这样的函数并期望能够在正文中使用transpose?我必须列出Transpose 以及我需要的其他线性代数运算吗?
    • 我确定有办法,但我不能直接看到,可能需要先进行一些重组。 感觉就像你在试图硬塞一个类似 Java 的范式 - 使用特征代替接口 - 这并不真正符合人们在 Rust 中编程的方式。
    【解决方案2】:

    当两种类型需要关联时,最好的解决方案往往是associated types。这排除了像 trait 对象那样使用动态调度,但动态调度在 Rust 中仍然非常有限。 Rust 在静态调度方面更具表现力,相关类型利用了这一点。

    pub trait RowVector<Element>: Sized {
        type Transpose: ColumnVector<Element>;
    
        fn transpose(self) -> Self::Transpose;
    }
    
    pub trait ColumnVector<Element>: Sized {
        type Transpose: RowVector<Element>;
    
        fn transpose(self) -> Self::Transpose;
    }
    
    pub struct VecRowVector<Element> {
        pub vec: Vec<Element>
    }
    
    pub struct VecColumnVector<Element> {
        pub vec: Vec<Element>
    }
    
    impl<Element> RowVector<Element> for VecRowVector<Element> {
        type Transpose = VecColumnVector<Element>;
    
        fn transpose(self) -> VecColumnVector<Element> {
            VecColumnVector { vec: self.vec }
        }
    }
    
    impl<E: Debug> ColumnVector<Element> for VecColumnVector<Element> {
        type Transpose = VecRowVector<Element>;
    
        fn transpose(self) -> VecRowVector<Element> {
            VecRowVector { vec: self.vec }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-07
      • 1970-01-01
      • 1970-01-01
      • 2013-10-31
      • 2015-03-23
      • 2017-09-05
      • 1970-01-01
      • 2019-04-04
      相关资源
      最近更新 更多