如何引用数组中的多个成员?

时间:2014-05-17 04:01:12

标签: rust

我有两个玩家阵列。我有一个变量current_num,它等于数组中哪个玩家是当前玩家。我有一个while循环遍历主游戏逻辑,有时current_num更新,有时它保持不变。我想在循环的每次迭代中分配一个current_player和next_player变量,如下所示:

while !self.board.check_win() {
   let ref mut current_player = self.players[current_num];
   let ref mut next_player = self.players[(current_num+1)%2];
   /* Game Logic */
}

这不起作用,因为我试图从self.players [..]借两次东西。老实说,如果我能以某种方式将下一个玩家存储在第一个玩家对象中,我甚至不需要next_player变量,但你似乎无法创建生锈的循环数据结构。我用编译器努力奋斗以完成以下任务:

player1.next = &player2;
player2.next = &player1;

不幸的是,这似乎不可能......如果是的话,我宁愿这样做,以便我可以做一些事情:

current_player.next().do_something();

而不是需要next_player变量。我也能做到:

current_player = current_player.next();

切换到下一个玩家所以我甚至不需要保留索引变量(current_num)。

现在我有一个工作模式,我总是把当前的玩家称为:

self.players[current_num].do_something()       //current_player
self.players[(current_num+1)%2).do_something() //next_player

这可以避免借用问题,但却会产生难以阅读的非常冗长的代码。在使这种设计工作方面,C / C ++真的要容易得多。我觉得我经常与编译器对抗以获得我想要的东西......

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

要解决您的直接问题,您可以使用the mut_split_at method,这会在内部使用unsafe代码为您提供两个不相交的切片到一个向量中,解决所有借用问题。您可以编写一个包装器,如:

fn double_index<'a, T>(x: &'a mut [T],
                       i: uint, j: uint) -> (&'a mut T, &'a mut T) {
    assert!(i != j, "cannot double_index with equal indices");

    if i < j {
        let (low, hi) = x.mut_split_at(j);

        (&mut low[i], &mut hi[0])
    } else { // i > j
        let (low, hi) = x.mut_split_at(i);

        (&mut hi[0], &mut low[j])
    }
}

然后写

let (current_player, next_player) = double_index(self.players,
                                                 current_num,
                                                 (current_num + 1) % 2);

(假设self.players[Player, .. 2]&mut [Player]。如果是Vec<Player>,您需要明确调用.as_mut_slice()。)


  

你似乎无法在生锈中创建循环数据结构

您可以使用Rc and Weak。对于共享可变性,您需要使用RefCellCell。 E.g。

use std::rc::{Rc, Weak};
use std::cell::RefCell;

struct Player {
    // ...
    next: Option<Weak<RefCell<Player>>>
}

impl Player {
    fn next(&self) -> Rc<RefCell<Player>> {
         // upgrade goes from Weak to Rc & fails if this is invalid
         self.next.unwrap().upgrade()
    }
}

let player1 = Rc::new(RefCell::new(Player { ..., next: None }));
let player2 = Rc::new(RefCell::new(Player { ..., next: None }));

// join them up; downgrade goes from Rc to Weak
player1.borrow_mut().next = Some(player2.downgrade());
player2.borrow_mut().next = Some(player1.downgrade());
  

这可以避免借用问题,但却会产生难以阅读的非常冗长的代码。在使这种设计工作方面,C / C ++真的要容易得多。我觉得我经常与编译器对抗以获得我想要的东西......

任何形式的共享可变性都很容易出错;并且在没有GC的语言中,这可能导致悬空指针,段错误和安全漏洞。不幸的是,以Rust的方式密封所有的孔会导致这种类型的东西有时相当难看。

答案 1 :(得分:1)

可替换地:

use std::cell::RefCell;

struct Player;

fn main() {

    let players = Vec::from_fn(3, |_| RefCell::new(Player));

    let mut player_1 = players.get(0).borrow_mut();
    let mut player_2 = players.get(1).borrow_mut();
    //Happily mutate both players from here on

}

通常不允许多次借用一个被借用的对象。你不能对同一个对象有多个&amp; mut引用,但是多个&amp; mut。允许引用,因为它们不允许变异。由于Cell和RefCell具有内部可变性,我们可以通过&amp;参考,同时仍然改变他们的内容。