终身问题传递& mut到函数并返回一个闭包

时间:2015-03-24 12:37:38

标签: closures rust mutable lifetime

我有一个简单的例子,通过分而治之来递增一个向量。非常基本,我只是不能让生命正确。我很确定它与&'s mut参数生存期和TaskResult<'s>返回生命周期有关,但我不确定如何使它工作。

code on the playpen

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     });

必须有一个简单的解决方法。我想说的是,我返回一个闭包向量,它对输入切片的某些部分有可变引用。我想我必须将闭包生命周期标记为比数据切片生命周期短,只是不确定如何做到这一点。

1 个答案:

答案 0 :(得分:2)

如果更改了一行,您可以编写并运行示例:

pub type MyClosure<'s> = FnOnce() -> TaskResult<'s> + Send + 's;
//                       ^~~~~~

我还在考虑如何解释它!

这是我开始的代码。我做了一些简化以开始,主要是删除不需要的生命周期参考。终身省略意味着fn(foo: &T) -> &Ufn<'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。你不能指向两次相同的可变事物)。如果你有FnMutFn,那么你可以多次调用闭包,这样就有机会创建别名。如果错误消息包含任何有关可变性的内容,那就太好了!

保证FnOnce只能被调用一次,这可以防止特定的别名机会。

我认为你可以提出1或2个错误:

  1. 令人惊讶的是,错误消息会根据是否存在let而发生变化。
  2. 提及可变性作为变量无法移入闭包的原因会很好。