如何捕获可变引用到从闭包返回的迭代器中包含的move闭包

vad*_*dix 2 closures rust

我有一个PRNG,我想通过可变引用允许闭包访问.理论上应该能够解决所有事物的生命周期,这就是它的样子:

fn someFunction<F, I>(mut crossover_point_iter_generator: F)
        where F: FnMut(usize) -> I, I: Iterator<Item=usize>;

let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
someFunction(|x| (0..3).map(move |_| rng.gen::<usize>() % x));
Run Code Online (Sandbox Code Playgroud)

这里,闭包创建一个包装PRNG生成的值的迭代器.这个迭代器包含一个带有闭包的映射,其中包含x克隆范围,但问题是它无意中克隆rng了,我已经验证过了.有必要使它成为一个移动闭包,因为x必须捕获值,否则闭包将比活动更长x.

我试图添加此行以强制它将引用移动到闭包中:

let rng = &mut rng;
Run Code Online (Sandbox Code Playgroud)

但是,Rust抱怨这个错误:

error: cannot move out of captured outer variable in an `FnMut` closure
Run Code Online (Sandbox Code Playgroud)

我可以从移动闭包内部可变地访问PRNG,如果没有,因为PRNG明显超过了函数调用,是否有替代解决方案(除了重新设计API)?

编辑:

我已经重写它以删除副本问题,并且调用如下所示:

someFunction(|x| rng.gen_iter::<usize>().map(move |y| y % x).take(3));
Run Code Online (Sandbox Code Playgroud)

这会导致新的错误:

error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
Run Code Online (Sandbox Code Playgroud)

blu*_*uss 5

你的情况需要多次冲突的可变借用,而rustc正在否定这一点.我们应该了解这种情况发生的原因和原因!

一个重要的说明:

  • Isaac64Rng实现Copy,这意味着它隐式复制而不仅仅是移动.我假设是遗留/向后兼容的东西.

我写了这个版本的代码来直截了当:

extern crate rand;

use rand::Isaac64Rng;
use rand::{Rng, SeedableRng};

fn someFunction<F, I>(crossover_point_iter_generator: F)
    where F: FnMut(usize) -> I, I: Iterator<Item=usize>
{
    panic!()
}

fn main() {
    let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
    let rng = &mut rng;  /* (##) Rust does not allow. */
    someFunction(|x| {
        (0..3).map(move |_| rng.gen::<usize>() % x)
    });
}
Run Code Online (Sandbox Code Playgroud)

让我把这点放在以下几点:

  • someFunction想要一个可以调用的闭包,每次调用它都会返回一个迭代器.闭包是可变的,可以多次调用(FnMut).

  • 我们必须假设所有返回的迭代器可以同时使用,而不是按顺序(一次一个).

  • 我们想借用Rng进入迭代器,但可变借用是独占的.因此,借用规则一次不允许多个迭代器.

  • FnOnce而不是FnMut将成为帮助我们的闭包协议的一个例子.它会使rustc看到只有一个迭代器.

在工作版本中,没有行(##),你有几个迭代器同时处于活动状态,那里发生了什么?这是隐式复制踢,所以每个迭代器将使用原始Rng的相同副本(听起来不合需要).

您的第二个版本的代码遇到了基本相同的限制.

如果您想解决借用的排他性问题,您可以使用特殊容器RefCellMutex序列化对Rng的访问.

  • *假设所有返回的迭代器可以同时使用* - + 1.这是恕我直言,将来学习帮助调试此类事情的关键. (2认同)