Rust实现Mancala时可变迭代器调用cycle()报Clone未实现错误
Rust实现Mancala播棋游戏的迭代逻辑报错问题
问题背景
- 和家人一同游玩Mancala(播棋)时体验很好,我很喜欢它简洁的规则,游玩时也产生了「游戏最高得分是多少」这类疑问,认为用Rust实现这个小游戏会很有趣,目前开发遇到阻碍需要解决。
规则与棋盘结构
- 本次实现的是经典版本的Mancala规则,了解规则有助于理解问题,不了解规则也可直接定位代码问题。
- 棋盘结构如下:
| |04|04|04|04|04|04| | |00|-----------------|00| | |04|04|04|04|04|04| |
- 每个数字代表一个棋洞,两侧大框内的数字代表
mancala(得分仓):得分仓是统计玩家分数的特殊棋洞,玩家右侧是己方得分仓,左侧是对手得分仓,数字代表对应位置存放的弹珠数量。 - 核心行棋规则:玩家选中一个棋洞取出所有弹珠,依次向后续每个棋洞/己方得分仓投放1颗弹珠直到用完,投放时需跳过对手得分仓,这部分是当前的实现难点。
现有实现方案
- 实现思路:
Board结构体用4个数组存储Hole(棋洞),分别对应两名玩家的侧边棋洞、双方的得分仓。计划链式拼接3组棋洞数组(跳过对手得分仓)后循环迭代,对这些Hole调用关联方法完成弹珠投放逻辑。 - 完整实现代码:
pub const STARTING_MARBLES: i8 = 4; pub const NO_OF_HOLES_OF_EACH_PLAYER: usize = 6; // 对局的两名玩家 #[derive(Debug, Copy, Clone)] pub enum Player { A, B, } // 棋盘上可存放弹珠的棋洞结构 #[derive(Debug, Copy, Clone)] struct Hole { marbles: i8, } impl Hole { // 向棋洞添加x颗弹珠 fn add_x(&mut self, x: i8) { self.marbles += x; } // 取出棋洞内所有弹珠,返回取出的弹珠数量 fn take_all(&mut self) -> i8 { let marbles = self.marbles; self.marbles = 0; marbles; } // 查询棋洞内当前的弹珠数量 fn count(&self) -> i8 { self.marbles } } // 播棋棋盘结构,包含所有普通棋洞和用于计分的双方得分仓 #[derive(Debug, Copy, Clone)] pub struct Board { holes_a: [Hole; NO_OF_HOLES_OF_EACH_PLAYER], holes_b: [Hole; NO_OF_HOLES_OF_EACH_PLAYER], mancala_a: [Hole; 1], mancala_b: [Hole; 1], } impl Board { // 初始化并返回开局状态的新棋盘 pub fn new() -> Self { let init_hole = Hole { marbles: STARTING_MARBLES, }; let holes_a = [init_hole; NO_OF_HOLES_OF_EACH_PLAYER]; let holes_b = [init_hole; NO_OF_HOLES_OF_EACH_PLAYER]; let mancala_a = [Hole { marbles: 0 }]; let mancala_b = [Hole { marbles: 0 }]; Board { holes_a, holes_b, mancala_a, mancala_b, } } // 选中棋洞行棋:取出选中洞的所有弹珠,依次投放到后续棋洞和己方得分仓 // player: 当前回合的玩家 // no: 选中棋洞的编号,从当前回合玩家最左侧的棋洞开始以0为起点计数 pub fn choose_hole(mut self, player: Player, no: usize) { let (mut players_own_holes, other_players_holes, players_mancala) = match player { Player::A => (self.holes_a, self.holes_b, self.mancala_a), Player::B => (self.holes_b, self.holes_a, self.mancala_b), }; let marbles_to_spend = players_own_holes[no].take_all() as usize; let holes_iter = self .holes_a .iter_mut() .chain(self.mancala_a.iter_mut()) .chain(self.holes_b.iter_mut()) .cycle() .skip(no + 1) .take(marbles_to_spend); for mut hole in holes_iter { hole.add_x(1); } } }
遇到的报错与异常
- 编译错误:使用
iter_mut()做链式拼接后调用cycle()方法时,编译器抛出如下错误:
error[E0277]: the trait bound `std::slice::IterMut<'_, Hole>: Clone` is not satisfied --> src/lib.rs:75:14 | 75 | .cycle() | ^^^^^ the trait `Clone` is not implemented for `std::slice::IterMut<'_, Hole>` | = note: required because of the requirements on the impl of `Clone` for `std::iter::Chain<std::iter::Chain<std::slice::IterMut<'_, Hole>, std::slice::IterMut<'_, Hole>>, std::slice::IterMut<'_, Hole>>` note: required by a bound in `cycle` --> /home/batman/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:3262:23 | 3262 | Self: Sized + Clone, | ^^^^^ required by this bound in `cycle`
- 逻辑异常:尝试将
iter_mut()替换为into_iter()后,代码不再触发编译报错,但运行时棋洞的弹珠数没有任何变化,推测是迭代过程操作的是数据副本,副本离开作用域后原数据未被修改,导致逻辑未生效。
内容的提问来源于stack exchange,提问作者Tom Smith
相关产品推荐
相关产品推荐

