You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 18:03:15