将 Vec<Rc<RefCell<T>>> 变成 &[&mut T]

Turning a Vec<Rc<RefCell<T>>> into a &[&mut T]

我有一个引用计数的向量 RefCells 并且想将 Vec 的 (mut) 引用传递给 RefCells 到功能。引用不需要超过函数调用。

看起来应该是可以的(只有一个,像&*x.borrow_mut()这样的就可以了)。我试图保留 RefMut&mut 的中间向量来控制生命周期,但我还没有找到让它工作的方法:

use std::cell::{RefCell,RefMut};
use std::vec::Vec;
use std::rc::Rc;

trait SomeTrait {}

struct Wrapper<'a> {
    pub r: &'a mut SomeTrait,
}

fn foo(_: &[Wrapper]) {}

fn main() {
    let mut v1: Vec<Rc<RefCell<SomeTrait>>> = unimplemented!();

    let mut v_rm: Vec<RefMut<_>> = v1.iter_mut().map(|r| r.borrow_mut()).collect();
    let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
    foo(&v_wrapper[..]);
}

(playground)

显然存在终身问题:

rustc 1.11.0 (9b21dcd6a 2016-08-15)
error: borrowed value does not live long enough
  --> <anon>:17:60
   |>
17 |>     let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
   |>                                                            ^^^^^^^^^^
note: reference must be valid for the block suffix following statement 2 at 17:107...
  --> <anon>:17:108
   |>
17 |>     let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
   |>                                                                                                            ^
note: ...but borrowed value is only valid for the block at 17:71
  --> <anon>:17:72
   |>
17 |>     let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
   |>                                                                        ^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

我控制 foo 所以可以改变它的 API 让事情变得更容易,但它在不同的 module/crate 我真的不希望它需要知道我将 SomeTrait 对象保存在 Rc<RefCell<_>>.

虽然可以编写以 Vec<RefMut<T>> 开头并从中创建 Vec<&mut T> (generic example) 的代码,但我建议您更改 foo。许多算法不需要切片提供的随机访问,如果函数可以接受迭代器而不是切片,则不需要创建 two 整个额外的 Vec s,除了调用函数变得更简单。我在想这样的签名

fn foo<I, R>(widgets: I)
    where I: IntoIterator<Item=R>,
          R: DerefMut<Target=SomeTrait>
{
    for widget in widgets {
        // ...
    }
}

那么您所需要的就是生成一个产生 RefMut 的迭代器,这很容易用 v1.iter_mut().map(|x| x.borrow_mut()) 完成。 Here's一个例子。

首先,我同意@delnan 的观点,如果可以的话,您应该切换到基于迭代器的界面。

这段代码的大部分都很好,在将 fooWrapper 更改为更加灵活之后,我能够调整其余部分并使其编译:

use std::cell::{RefCell,RefMut};
use std::vec::Vec;
use std::rc::Rc;

trait SomeTrait {}

struct Wrapper<'a, 'b> where 'b: 'a {
    pub r: &'a mut (SomeTrait + 'b),
}

fn foo<'a, 'b>(_: &'a mut [Wrapper<'a, 'b>]) where 'b: 'a {}

fn main() {
    let mut v1: Vec<Rc<RefCell<SomeTrait>>> = unimplemented!();

    let mut v_rm: Vec<RefMut<_>> = v1.iter_mut().map(|r| r.borrow_mut()).collect();
    let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|mut rm| Wrapper{ r: &mut **rm }).collect();
    foo(&mut v_wrapper[..]);
}

这里要理解的关键是每个 trait 对象类型都有一个固定的隐式生命周期,因为 impl 可能包含引用。没有 SomeTrait 这样的类型,只有 SomeTrait + 'aSomeTrait + 'bSomeTrait + 'static.

您的代码中的问题是 Rust 推断的两件事之间的不匹配。

  • 你写 Rc<RefCell<SomeTrait>> 的地方,Rust 假定你的意思是 Rc<RefCell<SomeTrait + 'static>>.

  • 你写 fn foo(_: &[Wrapper]) {} 的地方,应用了不同的规则,Rust 假设你的意思是 fn foo<'a>(_: &'a [Wrapper<'a> + 'a]).

哦。在这些假设下,这个谜题确实没有解,这就是为什么我不得不放松的原因。

如果您不想要那个 'b 生命周期参数,您可以放弃它,只需在使用它的地方(在类型上)将 'b 更改为 'static Wrapper::r)。这不太灵活:您将被限制为具有静态生命周期的 SomeTrait impls。