closures - 将 &mut 传递给函数并返回闭包的生命周期问题

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

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

最佳答案

如果你改变一行,你可以让你的例子编译并运行:

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 不允许可变引用的别名(也就是你不能指向同一个可变对象两次)这一事实。如果你有一个 FnMutFn ,那么您可以多次调用闭包,这将提供创建别名的机会。不过,如果错误消息包含有关可变性的任何内容,那就太好了!

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

我认为您可以从中提交 1 或 2 个错误:

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

关于closures - 将 &mut 传递给函数并返回闭包的生命周期问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29232849/

相关文章:

build - 如何在 Rust 中获取源代码的哈希值

performance - 可变的(可能是并行的)Haskell 代码和性能调优

jquery - 在闭包中使用 'this'

groovy - 为什么 Groovy 闭包声明一个最大值,而不是常量数量的参数

rust - 是否有一种习惯用法可以将 var 分配给不安全调用的结果并稍后使用该 var 而无需将其他所有内容嵌套在 unsafe{} 内?

rust - 为什么即使第一个已经超出范围,借用检查器也不允许第二个可变借用?

reference - 引用的身份关闭

swift - 如果它比一条语句更复杂,则变异闭包不会编译——如何修复?

reactjs - 在 React 中使用 splice 更新状态

java - 可变类和不可变类