IntoIterator 类型的 trait 对象可以装箱并保存在结构内吗?

wye*_*r33 3 rust

可以将 trait 类型的对象IntoIterator装箱并保存在结构内吗?我有一种情况,我想存储一个可以变成迭代器的对象向量。我在这方面的尝试是代码

struct Foo {   
    foo: Vec<Box<dyn IntoIterator<Item = usize>>>,
}                                                            
                 
fn main() {                                                                     
    let _ = Foo {                                                               
        foo: vec![Box::new(1..2), Box::new(vec![2,4,4])],                       
    };                                                                          
}
Run Code Online (Sandbox Code Playgroud)

但是,这不会编译并产生错误:

error[E0191]: the value of the associated type `IntoIter` (from trait `IntoIterator`) must be specified
 --> src/main.rs:6:22
  |
6 |     foo: Vec<Box<dyn IntoIterator<Item = usize>>>,
  |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `IntoIterator<Item = usize, IntoIter = Type>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0191`.
Run Code Online (Sandbox Code Playgroud)

我知道大多数时候,当我们想要使用时,IntoIterator我们将泛型传递到结构中。但是,在这种情况下,我要存储的项目没有相同的时间。因此,有没有办法存储可以全部转换为相同类型迭代器的异构对象集合?

Nov*_*zen 6

你想做的事对我来说没有多大意义。但是很容易将 each 装箱Iterator而不是 each IntoIterator

struct Foo {   
    foo: Vec<Box<dyn Iterator<Item = usize>>>,
}                                                            
                 
fn main() {                                                                     
    let _ = Foo {                                                               
        foo: vec![Box::new((1..2).into_iter()), Box::new(vec![2,4,4].into_iter())],                       
    };                                                                          
}
Run Code Online (Sandbox Code Playgroud)

您遇到的问题是这样IntoIterator定义的:

pub trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;
    fn into_iter(self) -> Self::IntoIter;
}
Run Code Online (Sandbox Code Playgroud)

为了让编译器发出单态代码,您必须在字段声明的说明符中指定Item类型和IntoIter类型。但是实现的不同类型具有不同的类型。dynfooIntoIteratorIntoIter

如果在IntoIterator对象真正变成Iterators之前将它们装箱对您来说真的很重要,那么您必须添加一个新的包装器,将所有不同的IntoIter类型转换为Box<dyn Iterator>. 像这样:

use std::iter::IntoIterator;

struct GenericIntoIterator<I: IntoIterator>(I);

impl<I: 'static + IntoIterator> std::iter::IntoIterator for GenericIntoIterator<I>
{
    type Item = <I as IntoIterator>::Item;
    type IntoIter = Box<dyn 'static + Iterator<Item = Self::Item>>;
    fn into_iter(self) -> Self::IntoIter {
        Box::new(self.0.into_iter())
    }
}

struct Foo {   
    foo: Vec<Box<dyn 'static + IntoIterator<Item = usize, IntoIter = Box<dyn 'static + Iterator<Item=usize>>>>>,
}                                                            
                 
fn main() {                                                                     
    let _ = Foo {                                                               
        foo: vec![Box::new(GenericIntoIterator(1..2)), Box::new(GenericIntoIterator(vec![2,4,4]))],                       
    };                                                                          
}
Run Code Online (Sandbox Code Playgroud)