在改变HashMap的一个元素

时间:2018-03-31 05:18:22

标签: rust

我正在开发一款涉及Beetle存储的HashMap个对象的游戏。每个甲虫都有一个位置,它也可以有一个目标id,它是哈希中另一个甲虫的关键。如果甲虫有目标,则每次游戏循环执行时都需要移动到目标。

我无法执行目标当前位置的查找,因为您不能同时拥有可变且不可变的借位。我知道了,但任何想法如何重组我的具体案例?

我认为我只是陷入了几乎任何其他语言的容易程度,我无法看到惯用的Rust方式来做到这一点。这是一个非常小但完整的例子:

use std::collections::HashMap;

type Beetles = HashMap<i32, Beetle>;

struct Beetle {
    x: f32,
    y: f32,
    target_id: i32,
}

impl Beetle {
    fn new() -> Beetle {
        Beetle {
            x: 0.0,
            y: 0.0,
            target_id: -1,
        }
    }
}

fn main() {
    let mut beetles: Beetles = HashMap::new();

    beetles.insert(0, Beetle::new());
    beetles.insert(1, Beetle::new());

    set_target(&mut beetles, 0, 1);
    move_toward_target(&mut beetles, 0);
}

fn set_target(beetles: &mut Beetles, subject_id: i32, target_id: i32) {
    if let Some(subject) = beetles.get_mut(&subject_id) {
        subject.target_id = target_id;
    }
}

fn move_toward_target(beetles: &mut Beetles, beetle_id: i32) {
    if let Some(subject) = beetles.get_mut(&beetle_id) {
        if let Some(target) = beetles.get(&subject.target_id) {
            // update subject position to move closer to target...
        }
    }
}

1 个答案:

答案 0 :(得分:3)

您可以通过对主题执行双重查找来解决您的特定问题。首先,从哈希映射中不可靠地借用以收集更新主题所需的信息。然后最后通过从哈希映射中可靠地借用来使用收集的信息更新主题:

fn move_toward_target(beetles: &mut Beetles, beetle_id: i32) {
    if let Some(subject_target_id) = beetles.get(&beetle_id).map(|b| b.target_id) {
        let mut target_xy = None; // example
        if let Some(target) = beetles.get(&subject_target_id) {
            // collect information about target relevant for updating subject
            target_xy = Some((target.x, target.y)) // example
        }
        let subject = beetles.get_mut(&beetle_id).unwrap();
        // update subject using collected information about target
        if let Some((target_x, target_y)) = target_xy{ // example
            subject.x = target_x;
            subject.y = target_y;
        }
    }
}

然而,未来你可能会遇到与甲虫类似且更复杂的问题,因为甲虫是你的中心游戏对象,你可能希望在几个时候同时可变地和不可变地引用甲虫代码中的位置。 因此,在std::cell::RefCell中包装甲虫是有意义的,它会在运行时动态检查借用规则。在哈希映射中引用甲虫时,这为您提供了很大的灵活性:

fn main() {
    let mut beetles: Beetles = HashMap::new();

    beetles.insert(0, RefCell::new(Beetle::new()));
    beetles.insert(1, RefCell::new(Beetle::new()));

    set_target(&mut beetles, 0, 1);
    move_toward_target(&mut beetles, 0);
}

fn set_target(beetles: &mut Beetles, subject_id: i32, target_id: i32) {
    if let Some(mut subject) = beetles.get_mut(&subject_id).map(|b| b.borrow_mut()) {
        subject.target_id = target_id;
    }
}

fn move_toward_target(beetles: &mut Beetles, beetle_id: i32) {
    if let Some(mut subject) = beetles.get(&beetle_id).map(|b| b.borrow_mut()) {
        if let Some(target) = beetles.get(&subject.target_id).map(|b| b.borrow()) {
            //example for updating subject based on target
            subject.x = target.x;
            subject.y = target.y;
        }
    }
}

更新Beetles类型:

type Beetles = HashMap<i32, RefCell<Beetle>>;