This is a contrived example but I believe if I can get this working I can apply it to my specific case.
extern crate num;
extern crate rayon;
use rayon::prelude::*;
use num::Float;
fn sqrts<T: Float>(floats: &Vec<T>) -> Vec<T> {
floats.par_iter().map(|f| f.sqrt()).collect()
}
fn main() {
let v = vec![1.0, 4.0, 9.0, 16.0, 25.0];
println!("{:?}", sqrts(&v));
}
This errors at compile time with "the method par_iter
exists but the following trait bounds were not satisfied: &std::vec::Vec<T> : rayon::par_iter::IntoParallelIterator
". The code works fine if I use iter
instead of par_iter
or if I switch to using f32
or f64
instead of the generic.
What can I do to be able to use par_iter
on a vector of generics? Is the IntoParallelIterator
trait meant to be implemented by the end user? How would I go about doing that?
First, read Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?. Then...
Review the implementors of IntoParallelIterator
:
impl<'data, T: Sync + 'data> IntoParallelIterator for &'data [T]
Adding the Sync
bound fixes that issue. Rayon works by potentially using multiple threads, but your original T
makes no guarantees about if it is safe to share or between threads! This comes up a second time:
error: no method named `collect` found for type `rayon::par_iter::map::Map<rayon::par_iter::slice::SliceIter<'_, T>, rayon::par_iter::map::MapFn<[closure@src/main.rs:7:27: 7:39]>>` in the current scope
--> src/main.rs:7:41
|
7 | floats.par_iter().map(|f| f.sqrt()).collect()
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied: `rayon::par_iter::map::MapFn<[closure@src/main.rs:7:27: 7:39]> : rayon::par_iter::map::MapOp<&_>`, `rayon::par_iter::map::Map<rayon::par_iter::slice::SliceIter<'_, T>, rayon::par_iter::map::MapFn<[closure@src/main.rs:7:27: 7:39]>> : std::iter::Iterator`
Checking out collect
:
fn collect<C>(self) -> C
where C: FromParallelIterator<Self::Item>
We can see that the target type needs to implement FromParallelIterator
:
impl<T> FromParallelIterator<T> for Vec<T> where T: Send
Thus, adding both bounds allows it to compile:
fn sqrts<T: Float + Send + Sync>(floats: &[T]) -> Vec<T>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With