2016-09-26 86 views
1

我有的引用计数RefCell个矢量和想要的(mut)引用一个Vec通入RefCell s转换的功能。这些引用不需要超过函数调用。车削A VEC <RC <RefCell<T> >>成&[&MUT T]

它似乎应该是可能的(只有一个,像&*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

首先,我同意@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 Rust推断的两件事情之间的不匹配。

  • 如果你写Rc<RefCell<SomeTrait>>,防锈假设你的意思是Rc<RefCell<SomeTrait + 'static>>

  • 你在哪写的fn foo(_: &[Wrapper]) {},应用了不同的规则,Rust认为你的意思是fn foo<'a>(_: &'a [Wrapper<'a> + 'a])

D'oh。在这些假设下,这个难题确实没有解决办法,这就是为什么我必须放松一些东西。

如果你不希望一辈子'b参数,你可以抛弃它,只是改变'b'static在使用它的一个地方(对Wrapper::r类型)。这不太灵活:您将被限制为SomeTrait impls具有静态生命周期。

+0

这很有用,谢谢。我想我可以在函数签名(至少有时候)中得到关于生命期限的规则。描述/记录的Rc >的推断“静态”在哪里? –

+0

我想我已经找到了它:[RFC 599](https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md) –

+0

...修正者[RFC 1156](https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md) –

3

虽然它肯定是可以编写一个Vec<RefMut<T>>启动并创建从(generic example)一Vec<&mut T>代码,我建议你改变foo签名。许多算法不需要切片提供的随机访问,如果函数可以接受迭代器而不是切片,则除了调用函数变得更简单之外,您不需要创建整个额外的Vec。我喜欢这个

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一个例子。

+0

您的'wrangle_mut_refs'示例是否从Vec >>开始工作?这与我所拥有的接近,似乎仍然无法解决我的代码存在的一生问题。 –

+0

更通用的版本看起来像一个改进,除了在这种情况下'foo'需要迭代多次,所以依靠'IntoIterator'可能不起作用。但是,也许使用'DerefMut'可以传递一段'RefMut'。 –

+1

@ChrisEmerson'wrangle_mut_refs'从'Vec >'工作,但在问题中,您已经成功从Vec >>创建了这个问题。 – delnan

相关问题