迭代器的 Rust "doesn't have a size known at compile-time" 错误?

Rust "doesn't have a size known at compile-time" error for iterators?

我正在重构 Rust 的 itertools [1] 中的笛卡尔积代码,作为学习 Rust 的一种方式。笛卡尔积由一个Iterator I和一个IntoIterator J组成。IntoIterator J多次转换为迭代器并迭代。

到目前为止我有下面的代码,这是对 itertools 源代码中的代码的一个小修改。最大的变化是指定特定类型 (i8) 而不是使用通用类型。

struct Product {
    a: dyn Iterator<Item=i8>,
    a_cur: Option<i8>,
    b: dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>,
    b_iter: dyn Iterator<Item=i8>
}


impl Iterator for Product {

    type Item = (i8, i8);

    fn next(&mut self) -> Option<Self::Item> {
        let elt_b = match self.b_iter.next() {
            None => {
                self.b_iter = self.b.into_iter();
                match self.b_iter.next() {
                    None => return None,
                    Some(x) => {
                        self.a_cur = self.a.next();
                        x
                    }
                }
            }
            Some(x) => x
        };
        match self.a_cur {
            None => None, 
            Some(ref a) => {
                Some((a, elt_b))
            }
        }

    }

}


fn cp(i: impl Iterator<Item=i8>, j: impl IntoIterator<Item=i8>) -> Product {
    
   let p = Product{
       a: i, 
       a_cur: i.next(), 
       b: j, 
       b_iter: j.into_iter()};
   return p

}



fn main() {

    for foo in cp(vec![1,4,7], vec![2,3,9]) {
        println!("{:?}", foo);
    }

}

不幸的是,编译器给出了我无法修复的错误。我已经尝试了编译器建议的修复,但是当我进行修复时,我得到了更多“在编译时不知道大小”的错误。

我特别困惑,因为 Rust 的 itertools 库(下面 link)中的实现具有非常相似的结构,不需要指定生命周期、借用、使用 Boxes 或 dyn 关键字。我很想知道我所做的更改导致 Rust 编译器建议使用借用 and/or 框。

error[E0277]: the size for values of type `(dyn Iterator<Item = i8> + 'static)` cannot be known at compilation time
  --> src/main.rs:15:8
   |
15 |     a: dyn Iterator<Item=i8>,
   |        ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = i8> + 'static)`
   = note: only the last field of a struct may have a dynamically sized type
   = help: change the field's type to have a statically known size
help: borrowed types always have a statically known size
   |
15 |     a: &dyn Iterator<Item=i8>,
   |        ^
help: the `Box` type always has a statically known size and allocates its contents in the heap
   |
15 |     a: Box<dyn Iterator<Item=i8>>,
   |        ^^^^                     ^

error[E0277]: the size for values of type `(dyn IntoIterator<Item = i8, IntoIter = (dyn Iterator<Item = i8> + 'static)> + 'static)` cannot be known at compilation time
  --> src/main.rs:17:8
   |
17 |     b: dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>,
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn IntoIterator<Item = i8, IntoIter = (dyn Iterator<Item = i8> + 'static)> + 'static)`
   = note: only the last field of a struct may have a dynamically sized type
   = help: change the field's type to have a statically known size
help: borrowed types always have a statically known size
   |
17 |     b: &dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>,
   |        ^
help: the `Box` type always has a statically known size and allocates its contents in the heap
   |
17 |     b: Box<dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>>,
   |        ^^^^                                                         ^

error: aborting due to 2 previous errors

[1] 文档位于 https://nozaq.github.io/shogi-rs/itertools/trait.Itertools.html#method.cartesian_product and code at https://github.com/rust-itertools/itertools/blob/master/src/adaptors/mod.rs#L286 .

您不仅更改了项类型,还删除了通用迭代器。在 itertools 箱子中,有:

pub struct Product<I, J>
    where I: Iterator
{
    a: I,
…

意味着 a 是一个迭代器,其确切类型将由用户指定(但仍在编译时)。

您删除了通用 I 参数,而是编写了:

pub struct Product
{
    a: dyn Iterator<Item=i8>,
…

如果有效,则意味着 a 是一个迭代器,其项类型为 u8 ,但其确切类型将在运行时指定。因此在编译时,编译器无法知道 a 的确切类型,也不知道应该分配多少 space 来存储 Product.

中的 a

如果您希望您的笛卡尔积适用于任何项目为 u8 的迭代器,您需要使用额外的约束来保留通用参数 I

pub struct Product<I, J>
    where I: Iterator<Item=u8>
{
    a: I,
…

impl Iterator 中的 J 也需要进行类似的更改。