在两个集合中共享引用变量

时间:2016-06-23 18:13:12

标签: rust

我正在尝试在两个集合中共享引用:地图和列表。我想推送到两个集合并从列表的后面删除并从地图中删除。这段代码只是一个展示我想要做的事情的样本,它甚至都没有编译!

实现这个的正确范例是什么?最佳做法是什么样的保证?

use std::collections::{HashMap, LinkedList};

struct Data {
    url: String,
    access: u64,
}

struct Holder {
    list: LinkedList<Box<Data>>,
    map: HashMap<String, Box<Data>>,
}

impl Holder {
    fn push(&mut self, d: Data) {
        let boxed = Box::new(d);
        self.list.push_back(boxed);
        self.map.insert(d.url.to_owned(), boxed);
    }

    fn remove_last(&mut self) {
        if let Some(v) = self.list.back() {
            self.map.remove(&v.url);
        }
        self.list.pop_back();
    }
}

2 个答案:

答案 0 :(得分:3)

同时在多个集合中存储单个项目的想法并不新鲜......并且不简单。

共享元素的常见想法是不安全地(知道有多少集合)或者使用共享指针进行操作。

使用共享指针盲目地使用常规集合会有一些低效率:

  • 基于节点的集合意味着您有双重间接
  • 从一个视图切换到另一个视图需要重新找到该元素

在Boost.MultiIndex(C ++)中,使用的范例是创建一个包含该值的侵入节点,然后在各个视图中链接该节点。诀窍(和难点)是以允许周围元素能够在O(1)或O(log N)中“取消链接”它的方式来制作侵入节点。

这样做会非常unsafe,除非您准备花费大量时间,否则我不建议您尝试使用它。

因此,为了快速解决方案:

type Node = Rc<RefCell<Data>>;

struct Holder {
    list: LinkedList<Node>,
    map: HashMap<String, Node>,
}

只要您不需要url删除,这就足够了。

完整示例:

use std::collections::{HashMap, LinkedList};
use std::cell::RefCell;
use std::rc::Rc;

struct Data {
    url: String,
    access: u64,
}

type Node = Rc<RefCell<Data>>;

struct Holder {
    list: LinkedList<Node>,
    map: HashMap<String, Node>,
}

impl Holder {
    fn push(&mut self, d: Data) {
        let url = d.url.to_owned();
        let node = Rc::new(RefCell::new(d));
        self.list.push_back(Rc::clone(&node));
        self.map.insert(url, node);
    }

    fn remove_last(&mut self) {
        if let Some(node) = self.list.back() {
            self.map.remove(&node.borrow().url);
        }
        self.list.pop_back();
    }
}

fn main() {}

答案 1 :(得分:1)

就个人而言,我会使用Rc代替Box

或者,您可以将索引存储到列表中作为哈希映射的值类型(即使用HashMap<String, usize>而不是HashMap<String, Box<Data>>

根据您的目的,最好只包含列表或地图,而不是两者。