2017-02-28 26 views
2

我想设计一对性状(例如线性代数中的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>` 

我不是做VecColumnVectorColumnVector亚型?或者,我是否需要告诉特征,它不需要是一生中的一个static

回答

2

您正试图返回一个特质。虽然这可以使用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) 
    } 
} 
+0

如何更新'RowVector'和'ColumnVector'特性以表示每个实现它们的结构必须也实现相应的'Transpose'? – drhagen

+0

我认为这会变得非常复杂:每个特征的约束之间会有循环引用,因为您必须以严格的对定义impls,这很难在Rust中表达。一个更简单(也更灵活)的设计是不对这些类型本身施加任何约束,而是对使用类型的地方施加约束。 –

+0

所以我不能编写像'f (r:&RowVector ,c:&ColumnVector )'这样的函数,并期望能够在体内使用'transpose'?我必须列出'Transpose'以及我将需要的其他线性代数运算? – drhagen

1

当两种类型都需要进行相关,最好的解决办法往往是associated types。这排除了像特质对象那样使用动态分派,但动态分派在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 } 
    } 
}