我正在尝试实现像拉链这样的东西,但是利用可变引用来避免在我移动时不得不解构和重构数据结构.我有一个链接列表尝试的示例代码,尽管我最好将其应用于其他结构,如树.
pub enum List<T> {
Empty,
Cons { head: T, tail: Box<List<T>> },
}
pub struct Zipper<'a, T: 'a> {
trail: Option<Box<Zipper<'a, T>>>,
focus: &'a mut List<T>,
}
impl<'a, T: 'a> Zipper<'a, T> {
pub fn down(&'a mut self) {
match self.focus {
&mut List::Empty => (),
&mut List::Cons {
tail: ref mut xs, ..
} => {
//We need a way to convince rust that we won't use oldZipper
//until xs goes out of scope
let oldZipper = std::mem::replace( …Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个返回某种列表的函数。由于这个函数是纯函数,并且我可能会多次调用它,因此我想缓存结果。为了避免分配,我想返回所有都指向同一内存位置的引用,这样我只需要在每次函数的唯一调用时执行一次分配。
原则上,我可以将每个结果作为向量存储在缓存中,并返回对结果向量切片的引用。这看起来不安全,但(我认为)事实并非如此。如果您从不删除或修改缓存的元素,那么您的切片引用就是安全的。当您添加到缓存时,矢量可能会移动,但它们的切片不应移动。
显然借用检查器不会接受这个解决方案。就其而言,当函数返回时,缓存被借用,并且您不能再次调用它,因为这需要可变借用。
到目前为止,我拥有的最佳解决方案是在此处的操场上,包括如下:
use std::collections::HashMap;
use std::rc::Rc;
fn n_trues(n: usize, cache: &mut HashMap<usize, Rc<[bool]>>) -> Rc<[bool]> {
cache
.entry(n)
.or_insert_with(|| vec![true; n].into())
.clone()
}
fn main() {
let mut cache = HashMap::new();
let zero = n_trues(0, &mut cache);
let one = n_trues(1, &mut cache);
let other_zero = n_trues(0, &mut cache);
assert!(Rc::ptr_eq(&zero, &other_zero));
for x in [zero, one, other_zero].iter() {
println!("{:?}", x);
}
}
Run Code Online (Sandbox Code Playgroud)
满足Rc借用检查器:从缓存中删除不会使其他引用无效,并且您不能改变Rc. 然而,实际的引用计数是多余的:我们确保缓存仅在程序结束时超出范围,因此在此之前缓存的值不会被释放。这是借用检查器可以检查的事情:它可以确保缓存的寿命比所有结果都长。
有没有什么方法可以消除引用计数而不诉诸不安全代码?