大小问题动态调度迭代器rust

kq0g1dla  于 2023-06-30  发布在  其他
关注(0)|答案(2)|浏览(79)

我正在实现一个结构体,它包含一个对状态集合的引用,并且能够以循环的方式遍历该引用。

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()) }
    }
}

构造函数和tick方法正常工作。但是我也想为这个结构体实现Clone。这就是我迷路的地方:

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>`

由于动态分派的原因,我似乎不能用编译时未知的东西来创建新的Box。我知道这将始终是一个指向u8的迭代器,但我不知道如何告诉编译器。

bmvo0sr5

bmvo0sr51#

因为你知道_state的实际类型,并且它是Sized,所以你可以去掉所有的trait对象,直接定义它。

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() }
    }
}

注意,如果你不知道_state的确切类型,只知道它是一个产生u8 s的迭代器,你仍然可以定义clone,如果你在Pawn中参数化它的类型。考虑:

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(),
        }
    }
}
nkkqxpd9

nkkqxpd92#

也许你在这个问题上简化了很多,但是如果这是你的用例,我觉得它有点过度设计了。也许你可以考虑一个更简单的设计,比如

#[derive(Clone, Copy)]
struct SimplePawn {
    state: u8,
}

impl SimplePawn {
    const STATES: usize = 10;

    fn new() -> Self {
        Self {
            state: 1,
        }
    }

    fn tick(&mut self, steps: usize) -> u8 {
        let mut state = self.state as usize - 1;
        state = (state + steps - 1) % Self::STATES + 1;
        let state = state as u8;
        self.state = state + 1; 
        state
    }
}

#[test]
fn test_equivalent() {
    // Where `Pawn` is the type that @AdamSmith suggested
    let mut pawn = Pawn::new();
    let mut simple_pawn = SimplePawn::new();
    
    for ticks in 1..1000 {
        assert_eq!(pawn.tick(ticks), simple_pawn.tick(ticks));
    }
}

相关问题