我正在尝试在两个集合中共享引用:地图和列表。我想推送到两个集合并从列表的后面删除并从地图中删除。这段代码只是一个展示我想要做的事情的样本,它甚至都没有编译!
实现这个的正确范例是什么?最佳做法是什么样的保证?
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();
}
}
答案 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>>
。
根据您的目的,最好只包含列表或地图,而不是两者。