Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sized question dynamic dispatch Iterator rust

Tags:

rust

I'm implementing a struct that holds a reference to a collection of states and able to walk that reference in a cyclic manner.

struct Pawn {
    _state: Box<dyn Iterator<Item = u8>>,
}

impl Pawn {

    const ALL_STATES: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    fn new() -> Self {
        Pawn { _state: Box::new(Self::ALL_STATES.into_iter().cycle()) }
    }

    fn tick(&mut self, steps: usize) -> u8 {
        (0..steps - 1).for_each(|_| {self._state.next();});
        self._state.next().unwrap()
    }
}

impl Clone for Pawn {

    fn clone(&self) -> Self {
        Self { _state: Box::new(*self._state.as_ref().clone()) }
    }
}

The constructor and the tick method work as they should. But I'd like to implement Clone for this struct as well. This is where I get lost:

the size for values of type `dyn Iterator<Item = u8>` cannot be known at compilation time
the trait `Sized` is not implemented for `dyn Iterator<Item = u8>`

It seems that I cannot make a new Box out of something that is not known at compile time, due to the dynamic dispatch. I know this will always be an iterator pointing to a u8, but I don't know how to tell the compiler.

like image 1000
hasdrubal Avatar asked Sep 14 '26 20:09

hasdrubal


1 Answers

Since you know the actual type of _state and it is Sized, you can do away with all the trait objects and just define it directly.


struct Pawn {
    _state: std::iter::Cycle<std::array::IntoIter<u8, 10>>
}

impl Pawn {
    fn new() -> Self {
        // as before, but remove Box::new
    }
}

impl Clone for Pawn {

    fn clone(&self) -> Self {
        Self { _state: self._state.clone() }
    }
}

N.B. that if you did not know the exact type of _state, only that it was an iterator that produced u8s, you could still define clone if you parameterize its type in Pawn. Consider:

struct Pawn<S>
where
    S: Iterator<Item = u8>,
{
    _state: S,
}

impl Pawn<std::iter::Cycle<std::array::IntoIter<u8, 10>>> {
    const ALL_STATES: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    fn new() -> Self {
        Pawn {
            _state: Self::ALL_STATES.into_iter().cycle(),
        }
    }

    fn tick(&mut self, steps: usize) -> u8 {
        (0..steps - 1).for_each(|_| {
            self._state.next();
        });
        self._state.next().unwrap()
    }
}

// Note the extra trait bound here! S must also be clone
impl<S> Clone for Pawn<S>
where
    S: Iterator<Item = u8> + Clone,
{
    fn clone(&self) -> Self {
        Self {
            _state: self._state.clone(),
        }
    }
}
like image 131
Adam Smith Avatar answered Sep 20 '26 10:09

Adam Smith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!