我有一个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));
在这里,闭包正在创建包装PRNG生成值的迭代器。该迭代器包含一个带有闭包的映射,该闭包具有将其包装范围x
克隆到其中的问题,但是问题在于它也无意地进行了克隆rng
,这已得到我的验证。必须将其设为移动闭包,因为x
必须捕获的值,否则闭包将失效x
。
我试图添加此行以强制其将引用移至闭包中:
let rng = &mut rng;
但是,Rust抱怨此错误:
error: cannot move out of captured outer variable in an `FnMut` closure
我是否可以从move闭包内部可变地访问PRNG,如果不能,因为PRNG显然比函数调用寿命更长,是否有替代解决方案(除了重新设计API外)?
编辑:
我已将其重写以消除复制问题,并且呼叫如下所示:
someFunction(|x| rng.gen_iter::<usize>().map(move |y| y % x).take(3));
这导致一个新的错误:
error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
您遇到的情况是需要多次相互冲突的可变借用,而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)
});
}
让我指出这一点:
someFunction
想要一个可以调用的闭包,每次调用时都返回一个迭代器。闭包是可变的,可以调用多次(FnMut
)。
我们必须假设所有返回的迭代器可以同时使用,而不是顺序使用(一次使用)。
我们想将Rng借给迭代器,但可变借项是排他的。因此,借用规则一次不允许有多个迭代器。
用FnOnce代替FnMut将是一种封闭协议的示例,可以在这里为我们提供帮助。这会让rustc看到只能有一个迭代器。
在工作版本中,没有line (##)
,您同时有多个活动的迭代器,那里发生了什么?这是隐式复制的开始,因此每个迭代器都将使用原始Rng的相同副本(听起来不受欢迎)。
您的第二个代码版本遇到了基本上相同的限制。
如果要解决借款的排他性问题,可以使用特殊容器,例如RefCell
或Mutex
序列化对Rng的访问。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句