gpt4 book ai didi

rust - 如何避免使用 IntoParallelIterator 绑定(bind)的可变和不可变借用

转载 作者:行者123 更新时间:2023-12-05 03:18:21 25 4
gpt4 key购买 nike

我有一个在 Vec<T> 上运行的函数其目的是使用对现有项目的引用生成的新项目来扩展向量。我正在尝试使用 rayon 并行运行新数据的生成.

这是一个最小的例子:

use itertools::Itertools;
use rayon::prelude::*;

fn main() {
let mut foo = Foo {
data: (0..1000).into_iter().collect(),
};
foo.run();
}

struct Foo<T> {
data: Vec<T>,
}

type Pair<'a, T> = (&'a T, &'a T);

impl<'a, T: Clone + 'a> Foo<T>
where
Vec<Pair<'a, T>>: IntoParallelIterator<Item = Pair<'a, T>>,
[T; 2]: IntoParallelIterator,
Vec<T>: FromParallelIterator<<[T; 2] as IntoParallelIterator>::Item>,
{
fn run(&'a mut self) {
let combinations: Vec<Pair<'a, T>> = self
.data
.iter()
.combinations(2)
.map(|x| (x[0], x[1]))
.collect();

let mut new_combinations: Vec<T> = combinations
.into_par_iter()
.flat_map(|(a, b)| bar(a, b))
.collect();

self.data.append(&mut new_combinations);
}
}


fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
[a.clone(), b.clone()]
}

您可以找到 Playground 的链接 here .

构建上述示例会引发此错误:

error[E0502]: cannot borrow `self.data` as mutable because it is also borrowed as immutable
--> src/main.rs:36:9
|
17 | impl<'a, T: Clone + 'a> Foo<T>
| -- lifetime `'a` defined here
...
24 | let combinations: Vec<Pair<'a, T>> = self
| ___________________________----------------___-
| | |
| | type annotation requires that `self.data` is borrowed for `'a`
25 | | .data
26 | | .iter()
| |___________________- immutable borrow occurs here
...
36 | self.data.append(&mut new_combinations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

据我所知,因为我收集到 let new_combinations: Vec<T>不应该有对 self.data 的不可变引用理论上我应该能够可变地借用它来附加新的组合。但是,似乎 self.data'a借用这超出了此方法的范围。我找不到避免指定生命周期的方法 fn run(&'a mut self)因为我需要指定对 self.data 项的引用的生命周期活不过self在创建组合时。

有没有办法让这个方法按预期运行,那就是:1)选择一个引用列表self.data中的项目。 , 2) 应用创建新项目的函数 T并行,最后 3) 更新 self.data与新项目。

请注意,作为一种解决方法,可以返回 new_combinations从方法并将它们附加到 self.data分别。

如果所有这些都可以通过避免尽​​可能多的 collect() 来实现,那就太好了尽可能直接使用迭代器操作。

最佳答案

new_combinations 中的元素是克隆的,因此不再从 combinations 中借用。但是,您的注释声明 T: 'a,这意味着 Rust 必须将它们视为仍然借用。

我个人认为你对这里的生命周期注释太过分了,你可以删除几乎所有的生命周期注释。在大多数情况下,编译器非常擅长自动找出它们。

此外,可悲的是,您的特征限制被编译器提示误导了。一旦您指定 T: Clone + Send + Sync,它们都会自动完成。

给你:

use itertools::Itertools;
use rayon::prelude::*;

fn main() {
let mut foo = Foo {
data: (0..10).collect(),
};
foo.run();
println!("{:?}", foo.data);
}

struct Foo<T> {
data: Vec<T>,
}

type Pair<'a, T> = (&'a T, &'a T);

impl<T: Clone + Send + Sync> Foo<T> {
fn run(&mut self) {
let combinations: Vec<Pair<T>> = self
.data
.iter()
.combinations(2)
.map(|x| (x[0], x[1]))
.collect();

let mut new_combinations: Vec<T> = combinations
.into_par_iter()
.flat_map(|(a, b)| bar(a, b))
.collect();

self.data.append(&mut new_combinations);
}
}

fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
[a.clone(), b.clone()]
}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 2, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 5, 6, 5, 7, 5, 8, 5, 9, 6, 7, 6, 8, 6, 9, 7, 8, 7, 9, 8, 9]

此外,确实不需要 Pair 类型:

use itertools::Itertools;
use rayon::prelude::*;

fn main() {
let mut foo = Foo {
data: (0..10).collect(),
};
foo.run();
println!("{:?}", foo.data);
}

struct Foo<T> {
data: Vec<T>,
}

impl<T: Clone + Send + Sync> Foo<T> {
fn run(&mut self) {
let combinations: Vec<_> = self
.data
.iter()
.combinations(2)
.map(|x| (x[0], x[1]))
.collect();

let mut new_combinations: Vec<T> = combinations
.into_par_iter()
.flat_map(|(a, b)| bar(a, b))
.collect();

self.data.append(&mut new_combinations);
}
}

fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
[a.clone(), b.clone()]
}

关于你问题的最后一部分,要求尽可能删除所有 .collect() 调用:

遗憾的是,我认为您无法删除任何 collect()。至少不是您当前的代码布局。您肯定需要在 combinations()into_par_iter() 之间 collect(),而且您肯定还需要 collect()append 之前,因为您需要在写入之前释放对 self.data 的所有引用。

关于rust - 如何避免使用 IntoParallelIterator 绑定(bind)的可变和不可变借用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73733163/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com