我有一个引用计数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[..]);
}
显然存在终身问题:
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<_>>
中的对象。
答案 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你应该切换到基于迭代器的界面。
大部分代码都很好,在将foo
和Wrapper
更改为更灵活之后,我能够调整其余部分并将其编译为:
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 + 'a
或SomeTrait + 'b
或SomeTrait + '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。