是否有一个更友好的类似RefCell的对象?

时间:2015-10-27 16:22:03

标签: vector rust

我正在寻找一个类似于Vec<RefCell<T>>的课程,因为它是最终的所有者&amp;所有数据的分配器,但阵列的不同部分可以由多方无限地可靠地借用。

我强调无限期因为当然Vec<T>的部分也可以被多方共同借用,但这样做涉及进行分割,只有在各方借款后才能解决

Vec<RefCell<T>>似乎是一个充满危险的世界,许多丑陋的if语句检查borrow_state,似乎是unstable。如果你做错了什么,那么kablammo!恐慌!这不是借阅图书馆的样子。在借阅图书馆,如果你要求一本不存在的书,他们会告诉你“哦,它已经签出了。”爆炸中没有人死亡。

所以我想编写类似这样的代码:

let mut a = LendingLibrary::new();
a.push(Foo{x:10});
a.push(Foo{x:11});
let b1 = a.get(0); // <-- b1 is an Option<RefMut<Foo>>
let b2 = a.get(1); // <-- b2 is an Option<RefMut<Foo>>

// the 0th element has already been borrowed, so...
let b3 = a.get(0); // <-- b3 is Option::None 

这样的事情存在吗?或者是否有另一种规范方式来获得这种行为?一种“友好的RefCell”?

如果答案是肯定的,那还有一个线程安全变体吗?

2 个答案:

答案 0 :(得分:2)

RefCell并非专为长期借用而​​设计。典型的用例是,在函数中,您将借用RefCell(可变或不可变),使用该值,然后在返回之前释放借位。我很想知道您希望如何在单线程环境中从借用的RefCell中恢复。

RefCell等效的线程安全是RwLock。它具有try_readtry_write函数,如果仍然获取不兼容的锁(在任何线程上,包括当前线程),它们不会阻塞或发生混乱。与RefCell相反,如果锁定RwLock失败,则稍后重试是有意义的,因为另一个线程可能恰好同时锁定了它。

如果您最终总是使用writetry_write,而不是readtry_read,那么您应该使用更简单的Mutex。< / p>

答案 1 :(得分:1)

#![feature(borrow_state)]
use std::cell::{RefCell, RefMut, BorrowState};

struct LendingLibrary<T> {
    items: Vec<RefCell<T>>
}

impl<T> LendingLibrary<T> {
    fn new(items: Vec<T>) -> LendingLibrary<T> {
        LendingLibrary {
            items: items.into_iter().map(|e| RefCell::new(e)).collect()
        }
    }

    fn get(&self, item: usize) -> Option<RefMut<T>> {
        self.items.get(item)
            .and_then(|cell| match cell.borrow_state() {
                BorrowState::Unused => Some(cell.borrow_mut()),
                _ => None
            })
    }
}

fn main() {
    let lib = LendingLibrary::new(vec![1, 2, 3]);

    let a = lib.get(0); // Some
    let b = lib.get(1); // Some

    let a2 = lib.get(0); // None
}

这需要每晚发布才能使用。