为什么 Rust 在构造 nalgebra::MatrixN 时无法找出正确的 `from_iterator` 来使用?

Why is Rust unable to figure out the correct `from_iterator` to use when constructing a nalgebra::MatrixN?

我有一个结构定义为:

use nalgebra::{
    allocator::Allocator, DefaultAllocator, Dim, DimName, MatrixN, RowVectorN, VectorN, U1,
}; // 0.22.0

pub struct Filter<Order: Dim + DimName>
where
    DefaultAllocator:
        Allocator<f64, Order, Order> + Allocator<f64, Order> + Allocator<f64, U1, Order>,
{
    a: MatrixN<f64, Order>,
    b: VectorN<f64, Order>,
    c: RowVectorN<f64, Order>,
    d: f64,
    x: VectorN<f64, Order>,
}

在我的单元测试模块中,我想构造一个 Filter:

的实例
mod tests {
    use super::*;
    use nalgebra::U2;

    fn a_filter() -> Filter<U2> {
        let a: MatrixN<f64, U2> = MatrixN::from_iterator([1., -0., 1., 0.].into_iter());

        Filter {
            a,
            b: VectorN::zeros(),
            c: RowVectorN::zeros(),
            d: 0.,
            x: VectorN::zeros()
        }
    }
}

调用MatrixN::from_iterator()导致编译错误。调用 ::zeros():

时出现类似错误
error[E0034]: multiple applicable items in scope
  --> src/lib.rs:22:44
   |
22 |         let a: MatrixN<f64, U2> = MatrixN::from_iterator([1., -0., 1., 0.].into_iter());
   |                                            ^^^^^^^^^^^^^ multiple `from_iterator` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:26:25
   |
26 |             b: VectorN::zeros(),
   |                         ^^^^^ multiple `zeros` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:27:28
   |
27 |             c: RowVectorN::zeros(),
   |                            ^^^^^ multiple `zeros` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:29:25
   |
29 |             x: VectorN::zeros(),
   |                         ^^^^^ multiple `zeros` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

我不清楚为什么 Rust 无法找出正确的 from_iterator 来使用。是因为我必须在 Filter 的定义中指定 DefaultAllocator 吗?如果是这样,最干净的解决方法是什么?

TL; DR; A workaround 你的代码:

fn a_filter() -> Filter<U2> {
    let a = MatrixN::<f64, U2>::from_iterator([1.0, -0., 1., 0.].iter().copied());

    Filter {
        a,
        b: VectorN::<f64, U2>::zeros(),
        c: RowVectorN::<f64, U2>::zeros(),
        d: 0.,
        x: VectorN::<f64, U2>::zeros()
    }
}

你必须在 zeros() 的调用中指定顺序,而不是从 return 类型中猜测它。

from_iterator 有一个额外的问题,即 array::into_iter() 不是 return 对值的迭代器而是对值的引用,就像 iter()(是的,是令人费解的,并且有一个 lint,IIRC),所以你需要添加一个 copied() 来获得正确的迭代器类型。


这是显示错误的最少代码 (playground):

use nalgebra::{
    VectorN, U3
};
fn main() {
    let x: VectorN<f64, U3> = VectorN::zeros();
}

错误是:

error[E0034]: multiple applicable items in scope
 --> src/main.rs:5:40
  |
5 |     let x: VectorN<f64, U3> = VectorN::zeros();
  |                                        ^^^^^ multiple `zeros` found
  |
  = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
  = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
  = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
  = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

如果你仔细看候选人,他们只是以下的全名:

candidate #1: Matrix<N, R, C, _>
candidate #2: Matrix<N, R, Dynamic, _>`
candidate #3: Matrix<N, Dynamic, C, _>`
candidate #4: Matrix<N, Dynamic, Dynamic, _>`

所以他们与 Dynamic 事情有关...如果您查看 documentation it is not very helpful, but if you look at the example in the zeros() 函数,它有一个提示:

let v = Vector3::<f32>::zeros();
let dv = DVector::<f32>::zeros(3);
let m = Matrix2x3::<f32>::zeros();
let dm = DMatrix::<f32>::zeros(2, 3);

等等...它不是需要 0 个参数吗?好吧,看看代码,虽然文档没有说明,但看​​起来 zeros() 接受的参数与泛型类型中的 Dynamic 一样多。而Vector3<T>Vector<T, U3>的别名,DVector<T>Vector<T, Dynamic>的别名等等。

您可能仍然认为编译器无论如何都可以推导出函数,因为 return 类型和参数编号对于 zero() 的每个版本都是不同的,但这不是编译器的工作方式: Rust 中没有函数重载。如果函数名称解析为多个函数,则为错误。

考虑显示类似错误的更简单的代码:

struct Foo<T> {
    t: T,
}

impl Foo<u8> {
    fn new() -> u8 {
        0
    }
}

impl Foo<u32> {
    fn new() -> u32 {
        0
    }
}

fn main() {
    let t: u8 = Foo::new(); // error!
}

请注意,如果两个函数 return 类型相同或不同,甚至它们是否具有相同数量的参数都没有关系,这始终是编译器错误。

我的代码的解决方法是:

fn main() {
    let t: u8 = Foo::<u8>::new();
}