如何实现来自<T> 2d 数组的自定义结构的 From 特征?



我正在尝试为我的自定义结构实现From<T>特性,该结构采用泛型类型的动态大小的二维数组。

这是我到目前为止的代码(操场链接(:

pub struct Matrix<K> {
matrix: Vec<Vec<K>>,
}
impl<K, T, Row> From<T> for Matrix<K>
where
K: Clone,
T: AsRef<[Row]>,
Row: AsRef<[K]>,
{
fn from(m: T) -> Self {
Matrix {
matrix: m
.as_ref()
.to_vec()
.iter()
.map(|x| x.as_ref().to_vec())
.collect(),
}
}
}
fn main() {
let m = Matrix::from([[1, 2], [3, 4]]);
println!("{:#?}", m);
}

这是我收到的错误:

error[E0207]: the type parameter `Row` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:7:12
|
7 | impl<K, T, Row> From<T> for Matrix<K>
|            ^^^ unconstrained type parameter

当我实现下面代码块中的implement a from((方法时(因此在不实现From<T>特性的情况下(,程序确实按预期工作(playgorund链接(:

pub struct Matrix<K> {
matrix: Vec<Vec<K>>,
}
impl<K: Clone> Matrix<K> {
pub fn from<T, Row>(matrix: T) -> Self
where
T: AsRef<[Row]>,
Row: Clone + AsRef<[K]>,
{
Matrix {
matrix: matrix
.as_ref()
.to_vec()
.iter()
.map(|x| x.as_ref().to_vec())
.collect(),
}
}
}
fn main() {
let m = Matrix::from([[1, 2], [3, 4]]);
println!("{:#?}", m);
}

然而,我确实想知道如何使用From<T>特性来实现它,因为我希望我的实现与我为自定义矢量结构(操场链接(实现它的方式类似

pub struct Vector<K> {
vector: Vec<K>,
}
impl<K, T> From<T> for Vector<K>
where
K: Clone,
T: AsRef<[K]>,
{
fn from(v: T) -> Self {
let v = v.as_ref().to_vec();
Vector {
vector: v,
}
}
}
fn main() {
let v = Vector::from([1, 2]);
println!("{:#?}", v);
}

我知道我可以使用切片,但我真的想使用这样的代码:let m = Matrix::from([[1, 2], [3, 4]]);,而不是像let m = Matrix::from(&[&[1, 2], &[3, 4]]);,所以这就是我使用AsRef<[K]>的原因。

我该怎么解决这个问题?

impl<K, T, Row>不工作的原因是编译器的限制。

impl的任何类型参数都必须满足以下标准:

  • 它出现在impl的实现类型中,例如impl<T> Foo<T>
  • 对于特征impl,它出现在实现的特征中,例如impl<T> SomeTrait<T> for Foo
  • 它被绑定为关联类型,例如impl<T, U> SomeTrait for T where T: AnotherTrait<AssocType=U>

长话短说,您不能将随机泛型类型放入impl<gt;。每种类型都必须来自from<gt;列表或矩阵<gt;列表

我看到了几个潜在的解决方案:

  1. 不要对整体数据使用泛型类型,只对行使用泛型类型(这是我最终尝试的,请参阅下面的代码(
  2. 在矩阵列表中引入行类型:Matrix<TElem, TRow>。数据有一个Vec<TRow>
  3. 与2(Matrix<TElem, TRow>(相同,但有一个额外的PhantomData<TRow>,并保留数据的Vec<Vec<TElem>>

2和3可能会限制不同Matrix<X>类型之间的兼容性。

我为(1(找到的最简单的解决方案是这样的:

impl<T, K> From<&dyn AsRef<[T]>> for Matrix<K>
where K: Clone, T: AsRef<[K]> + Clone
{
fn from(m: &dyn AsRef<[T]>) -> Self {
Self {
matrix: m.as_ref().iter()
.map(|row| row.as_ref().to_vec())
.collect(),
}
}
}
fn main() {
let m = Matrix::from(&[[1, 2], [3, 4]] as &dyn AsRef<_>);
println!("{:#?}", m);
}

操场

as &dyn子句很不幸,但Rust不够聪明,无法理解这一点。它将&[1, 2]视为对具有2个元素的数组的引用。感觉它需要被推动,才能将其转换为切片,然后成为dyn特征参考。

这个ofc可以通过宏来简化,但有了宏会让整个From想法变得可疑,因为你可以制作一个宏来处理你想要的表单,并构造一个vec!直接使得:

matrix!([[1, 2], [3, 4]])

转化为:

Matrix { matrix: vec![vec![1, 2], vec![3, 4]] }

最新更新