转动Vec <rc <refcell <t>&gt;&gt;进入&amp; [&amp; mut T]

时间:2016-09-26 11:09:33

标签: rust lifetime

我有一个引用计数RefCell的向量,并希望将Vec个(mut)个引用传递到RefCell s函数中。引用不需要比函数调用更长。

似乎它应该是可能的(只有一个,像&*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以使事情变得更容易,但它位于不同的模块/箱子中,我真的不希望它需要知道我保留了SomeTrait Rc<RefCell<_>>中的对象。

2 个答案:

答案 0 :(得分:3)

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

Vec

然后您只需要生成一个产生fn foo<I, R>(widgets: I) where I: IntoIterator<Item=R>, R: DerefMut<Target=SomeTrait> { for widget in widgets { // ... } } 的迭代器,这可以通过RefMut轻松完成。 Here's一个例子。

答案 1 :(得分:2)

首先,我同意@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[..]);
}

这里要理解的关键是每个特征对象类型都有一个隐含的生命周期,因为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])

D'哦。在这些假设下,拼图确实没有解决方案,这就是我不得不放松的原因。

如果您不想要'b生命周期参数,则可以放弃它,只需将'b更改为使用'static的{​​{1}}(Wrapper::r类型SomeTrait 1}})。这不太灵活:你将被限制为具有静态生命的var time = new Date().getHours(); var greet = ['Wow you\'re up late! Good morning.', 'Good morning.', 'Good afternoon.', 'Good evening.']['000011111111222223333333'[time]]; console.log(greet); impls。