我有一个简单的例子,通过分而治之来递增一个向量。非常基本,我只是不能让生命正确。我很确定它与&'s mut
参数生存期和TaskResult<'s>
返回生命周期有关,但我不确定如何使它工作。
fn main() {
let mut data = vec![1,2,3,4,5,6,7,8,9];
let t = inc_vec(data.as_mut_slice());
}
pub type MyClosure<'s> = FnMut() -> TaskResult<'s> + Send + 's;
pub enum TaskResult<'s> {
Done(usize),
Fork(Vec<Box<MyClosure<'s>>>),
}
fn inc_vec<'s>(data: &'s mut [usize]) -> TaskResult {
if data.len() <= 4 {
inc_vec_direct(data)
} else {
inc_vec_fork(data)
}
}
fn inc_vec_fork<'s>(data: &'s mut [usize]) -> TaskResult<'s> {
let mid = data.len()/2;
let (l,r) = data.split_at_mut(mid);
let task_l: Box<MyClosure<'s>> = Box::new(move || {
inc_vec(l)
});
let task_r: Box<MyClosure<'s>> = Box::new(move || {
inc_vec(r)
});
TaskResult::Fork(vec![task_l, task_r])
}
fn inc_vec_direct(data: &mut [usize]) -> TaskResult {
for d in data {
*d += 1;
}
TaskResult::Done(1)
}
它给了我以下错误(截断,因为同一错误产生两次,一次用于task_l
,一次用于task_r
):
src/main.rs:26:17: 26:18 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
src/main.rs:26 inc_vec(l)
^
src/main.rs:25:55: 27:6 note: first, the lifetime cannot outlive the lifetime as defined on the block at 25:54...
src/main.rs:25 let task_l: Box<MyClosure<'s>> = Box::new(move || {
src/main.rs:26 inc_vec(l)
src/main.rs:27 });
src/main.rs:26:17: 26:18 note: ...so that closure can access `l`
src/main.rs:26 inc_vec(l)
^
src/main.rs:21:62: 33:2 note: but, the lifetime must be valid for the lifetime 's as defined on the block at 21:61...
src/main.rs:21 fn inc_vec_fork<'s>(data: &'s mut [usize]) -> TaskResult<'s> {
src/main.rs:22 let mid = data.len()/2;
src/main.rs:23 let (l,r) = data.split_at_mut(mid);
src/main.rs:24
src/main.rs:25 let task_l: Box<MyClosure<'s>> = Box::new(move || {
src/main.rs:26 inc_vec(l)
...
src/main.rs:25:38: 27:7 note: ...so that trait type parameters matches those specified on the impl (expected `TaskResult<'_>`, found `TaskResult<'s>`)
src/main.rs:25 let task_l: Box<MyClosure<'s>> = Box::new(move || {
src/main.rs:26 inc_vec(l)
src/main.rs:27 });
必须有一个简单的解决方法。我想说的是,我返回一个闭包向量,它对输入切片的某些部分有可变引用。我想我必须将闭包生命周期标记为比数据切片生命周期短,只是不确定如何做到这一点。
答案 0 :(得分:2)
如果更改了一行,您可以编写并运行示例:
pub type MyClosure<'s> = FnOnce() -> TaskResult<'s> + Send + 's;
// ^~~~~~
我还在考虑如何解释它!
这是我开始的代码。我做了一些简化以开始,主要是删除不需要的生命周期参考。终身省略意味着fn(foo: &T) -> &U
与fn<'a>(foo: &'a T) -> &'a U
相同,但与fn<'a>(foo: &'a T) -> &U
不一样。
fn main() {
let mut data = vec![1,2,3,4,5,6,7,8,9];
let t = inc_vec(data.as_mut_slice());
}
pub type MyClosure<'s> = FnMut() -> TaskResult<'s> + Send + 's;
pub enum TaskResult<'s> {
Done(usize),
Fork(Vec<Box<MyClosure<'s>>>),
}
fn inc_vec(data: &mut [usize]) -> TaskResult {
if data.len() <= 4 {
inc_vec_direct(data)
} else {
inc_vec_fork(data)
}
}
fn inc_vec_fork(data: &mut [usize]) -> TaskResult {
let mid = data.len() / 2;
let (l, r) = data.split_at_mut(mid);
let task_l: Box<MyClosure> = Box::new(move || inc_vec(l));
let task_r: Box<MyClosure> = Box::new(move || inc_vec(r));
TaskResult::Fork(vec![task_l, task_r])
}
fn inc_vec_direct(data: &mut [usize]) -> TaskResult {
for d in data { *d += 1; }
TaskResult::Done(1)
}
大多数情况下,我通过改变闭包来达到结果:
let task_l: Box<MyClosure> = Box::new(move || { let a = l; inc_vec(a)});
哪个应该是相同的代码。但是,这有错误:
error: cannot move out of captured outer variable in an `FnMut` closure
let task_l: Box<MyClosure> = Box::new(move || { let a = l; inc_vec(a)});
^
note: attempting to move value to here
let task_l: Box<MyClosure> = Box::new(move || { let a = l; inc_vec(a)});
^
help: to prevent the move, use `ref a` or `ref mut a` to capture value by reference
这使我尝试了各种Fn*
特征,FnOnce
正在工作。我认为这个解决方案归结为Rust不允许使用可变引用的别名(a.k.a。你不能指向两次相同的可变事物)。如果你有FnMut
或Fn
,那么你可以多次调用闭包,这样就有机会创建别名。如果错误消息包含任何有关可变性的内容,那就太好了!
保证FnOnce
只能被调用一次,这可以防止特定的别名机会。
我认为你可以提出1或2个错误:
let
而发生变化。