我正在通过实施矩阵数学来练习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);
似乎对我来说似乎受到了限制。有人能指出我正确的方向吗?
答案 0 :(得分:8)
T
不受编译器在实现的使用站点上看到的信息的约束。通过trait Matrix<T>
,单个类型可以是多个元素类型的矩阵,也就是说,在同一个程序中同时拥有impl Matrix<u8> for Foo
和impl Matrix<u16> for Foo
的人是完全合法的。如果发生这种情况,那么Foo + Foo
(即使用Add
实施)无法确定使用哪个T
:T = u8
和T = 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);
// ...
}
类型成为添加更多方法和特征实现等的地方。