简体   繁体   中英

Clonable iterator trait object

I'm trying to define a struct with a clonable iterator object. So far, I've reached to:

pub struct UseClonableIterator2<'a,T:'a> {
    it: &'a (Iterator<Item=T> + Clone)
}

Which does not compile because Clone is not a "builtin trait":

x.rs:2:33: 2:38 error: only the builtin traits can be used as closure or object bounds [E0225]
x.rs:2     it: &'a (Iterator<Item=T> + Clone)
                                       ^~~~~           
x.rs:2:33: 2:38 help: run `rustc --explain E0225` to see a detailed explanation

One option might be to add another type parameter for the Iterator, but this complicates definitions and I'd rather avoid it.

Do you need dynamic dispatch? If not, you should use generic parameters instead of trait objects -- it doesn't necessarily complicate the definition. Try this for example:

pub struct UseClonableIterator<I: Iterator + Clone> {
    it: I
}

Here you save the object that implements Iterator and Clone within your type. If you just want to have a reference to it, this is of course possible, too:

pub struct UseClonableIterator2<'a, I: Iterator + Clone + 'a> {
    it: &'a I
}

Note that in both examples we use static dispatch and monomorphization. This usually results in better performance.

However, this is not always possible -- sometimes dynamic dispatch with trait objects (like you tried to implement it) is needed. In that case you can only solve your problem by restructuring your code, since Rust does not allow trait objects of multiple traits yet.

If you need the iterator to be dynamically dispatched, meaning the Iterator implementation type cannot be a type parameter of UseClonableIterator , then I would solve this as follows using my dyn-clone crate.


use dyn_clone::{clone_trait_object, DynClone};

trait ClonableIterator: Iterator + DynClone {}

impl<I: Iterator + DynClone> ClonableIterator for I {}

clone_trait_object!(<T> ClonableIterator<Item = T>);

#[derive(Clone)]
struct UseClonableIterator<T> {
    it: Box<dyn ClonableIterator<Item = T>>,
}

fn main() {
    let thing1 = UseClonableIterator {
        it: Box::new(vec![1, 2, 3].into_iter()),
    };

    let thing2 = thing1.clone();

    // prints 1 2 3 from thing1's iterator
    for i in thing1.it {
        println!("{}", i);
    }

    // prints 1 2 3 from thing2's iterator
    for i in thing2.it {
        println!("{}", i);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM