如何查找无别名的数据结构

时间:2016-09-22 20:51:31

标签: rust borrow-checker

我正在与借款检查员Rust的最终老板作战。这是我正在研究的mio被动网络应用程序的简化版本。我花了太多时间为手头的任务找到合适的数据结构。我希望在迭代可以接受新连接的侦听套接字时注册连接。

请参阅以下代码,或在Rust playground上查看。 HashMap::get_mut会在self的1个字段中返回1个值的唯一借位,因此我无法将self传递给Thing::act。我理解为什么会发生这种情况,如何导致运行时问题,但不知道如何重构数据结构以避免此类问题。

use std::collections::HashMap;

trait ThingSet {
    fn register(&mut self, thing: Box<Thing>);
}

trait Thing {
    fn act(&mut self, reg: &mut ThingSet);
}

struct Stream;

impl Thing for Stream {
    fn act(&mut self, reg: &mut ThingSet) {}
}

struct Listener;

impl Thing for Listener {
    fn act(&mut self, reg: &mut ThingSet) {
        if true {
            let mut stream = Stream {};
            reg.register(Box::new(stream));
        }
    }
}

struct Loop {
    next: usize,
    things: HashMap<usize, Box<Thing>>,
}

impl Loop {
    fn new() -> Loop {
        Loop { next: 1, things: HashMap::new(), }
    }
    fn run(&mut self) {
        let mut needs_action = Vec::<&mut Box<Thing>>::new();
        {
            // modeling a connection on one of the listeners...
            if let Some(t) = self.things.get_mut(&1usize) {
                needs_action.push(t);
            }
        }
        for t in needs_action {
            t.act(self as &mut ThingSet);
        }
    }
}

impl ThingSet for Loop {
    fn register(&mut self, thing: Box<Thing>) {
        self.things.insert(self.next, thing);
        self.next += 1;
    }
}

fn main() {
    let mut l = Loop::new();
    let mut p1 = Listener {};
    let mut p2 = Listener {};
    l.register(Box::new(p1));
    l.register(Box::new(p2));
    l.run();
}

我可以找到很好的教程来解释借阅检查器的作用以及它不允许的内容。我找不到关于如何找到替代数据结构的好教程,我可以避免不允许的引用。

您能否就如何改造此特定问题提出建议?

1 个答案:

答案 0 :(得分:2)

我认为可以纠正这个具体问题,但我觉得这里可能存在更普遍的问题。如果我错了,请纠正我,但似乎您运行Loop::run它将扫描您的ThingSet然后通过某些条件在Thing缓冲区上添加needs_action的可变引用。这里的一般问题似乎是通过不同的迭代,rustc无法验证这些不同的调用将为您提供不同的可变引用或对同一元素的另一个可变引用。因此,您可以使用类似RefCell的内容强制执行运行时借阅检查(请参阅Jsor的回答),或者您可以从ThingSet获取所有权并替换您已取得的内容用别的东西 - 或者一起从集合中删除元素。

例如,获取元素的所有权并将其从ThingSet中删除,如下所示:

impl Loop {
    fn new() -> Loop {
        Loop { next: 1, things: HashMap::new(), }
    }
    fn run(&mut self) {
        let mut needs_action = Vec::<Box<Thing>>::new();

        // modeling a connection on one of the listeners...
        if let Some(t) = self.things.remove(&1usize) {
            needs_action.push(t);
        }

        for t in &mut needs_action {
            t.act(self as &mut ThingSet);
        }
    }
}