使用泛型的特征的毯子实现

时间:2015-08-04 12:27:00

标签: generics matrix rust

我正在通过实施矩阵数学来练习Rust,并且遇到了一些障碍。我定义了我认为与矩阵相关的特征。

Vec<Vec<T>>

我使用impl <T, U> Add for U where T: num::Num, U: Matrix<T> { type Output = U; fn add(self, _rhs: U) -> U { U::new_const(T::zero(), 5, 5) } } 进行了愚蠢的实施。我实现了所有方法并测试了它们。他们都在工作。现在我想简单地将两个矩阵一起添加。因此,如果不添加我知道将需要的行迭代器并执行我知道的添加实现,那么我将执行以下操作。

lib.rs:41:7: 41:8 error: the type parameter `T` is not constrained by the impl trait, self type, or predicates [E0207]
lib.rs:41 impl <T, U> Add for U where T: num::Num, U: Matrix<T> {
                ^
lib.rs:41:7: 41:8 help: run `rustc --explain E0207` to see a detailed explanation
error: aborting due to previous error
Could not compile `matrix`.
To learn more, run the command again with --verbose.
Compilation failed.

但我得到

char buf[1024];

FILE* fp = fopen("file.in", "r");
fgets(buf, sizeof(buf), fp);
fclose(fp);

// substitute '[' and ']' with a space

sscanf(buf, "%s%s%s%s", firstName, middleName, lastName, Country);
似乎对我来说似乎受到了限制。有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:8)

T不受编译器在实现的使用站点上看到的信息的约束。通过trait Matrix<T>,单个类型可以是多个元素类型的矩阵,也就是说,在同一个程序中同时拥有impl Matrix<u8> for Fooimpl Matrix<u16> for Foo的人是完全合法的。如果发生这种情况,那么Foo + Foo(即使用Add实施)无法确定使用哪个TT = u8T = u16工作

我认为解决此问题的最佳方法是删除T类型参数:给定类型只是一种元素上的矩阵(即使它是通用的),例如: Vec<Vec<T>>是一个超过T的矩阵,没有别的。这就像Iterator:给定类型只能产生一种类型的元素。

在代码中,这看起来像:

trait Matrix {
    type Elem: num::Num;

    fn dim(&self) -> (usize, usize);
    fn elem(&self, i: usize, j: usize) -> Option<&Self::Elem>;
    // ...
}

然后Add实现变为

impl<U> Add for U where U: Matrix {
    type Output = U;

    fn add(self, _rhs: U) -> U {
        U::new_const(U::Elem::zero(), 5, 5)
    }
}

然而,这也不起作用,因为它会遇到连贯性问题。编译器无法确定Add的此实现与Add的其他实现不重叠,因为可以为已经具有{{1}的类型实现Matrix以某种方式实现。可以通过创建包装类型来解决这个问题,并使用Add特征作为“后备存储”特征,即它“只是”控制内部表示。

Matrix

然后struct Matrix<T: Storage> { x: T } trait Storage { // renamed `Matrix` trait type Elem; fn dim(&self) -> (usize, usize); // ... } 类型成为添加更多方法和特征实现等的地方。