2

我有一个Vec盒装封口(Vec<Box<Fn(...) -> ...>>)。我可以vec.into_iter().map(...),但我不能将它与 Rayon's 一起使用。into_par_iter vec.into_par_iter().map(...)

这是一个最小化的示例(playground):

type GameResult<T> = Result<T, ()>;
type Game = ();
type PlayerId = String;

use rayon::prelude::*; // 1.5.1

fn main() {
    // the type of our closures. It's boxed, so it's sized right?
    type CpuOption = Box<dyn Fn(u32) -> GameResult<u32>>;
    let mut options: Vec<CpuOption> = vec![];

    options.push(Box::new(|i| Ok(i + 2)));
    options.push(Box::new(|i| Ok(i + 3)));

    let try_it = |option: CpuOption| -> GameResult<u32> { Ok(option(12)?) };

    let parallel = true;

    if parallel {
        // ERROR IS HERE. says my type isn't sized?
        let options = options
            .into_par_iter()
            .map(try_it)
            .flat_map_iter(Result::into_iter);
        let best_option = options.max_by_key(|score| *score).unwrap();
    } else {
        // but this works fine!
        let options = options.into_iter().map(try_it).flat_map(Result::into_iter);
        let best_option = options.max_by_key(|score| *score).unwrap();
    }
}

我得到的错误:

   Compiling playground v0.0.1 (/playground)
error[E0599]: the method `into_par_iter` exists for struct `Vec<Box<(dyn Fn(u32) -> Result<u32, ()> + 'static)>>`, but its trait bounds were not satisfied
  --> src/lib.rs:24:14
   |
24 |             .into_par_iter()
   |              ^^^^^^^^^^^^^ method cannot be called on `Vec<Box<(dyn Fn(u32) -> Result<u32, ()> + 'static)>>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `[Box<dyn Fn(u32) -> Result<u32, ()>>]: Sized`
           which is required by `[Box<dyn Fn(u32) -> Result<u32, ()>>]: rayon::iter::IntoParallelIterator`
           `[Box<dyn Fn(u32) -> Result<u32, ()>>]: rayon::iter::ParallelIterator`
           which is required by `[Box<dyn Fn(u32) -> Result<u32, ()>>]: rayon::iter::IntoParallelIterator`

我的印象是,将封口包裹在盒子中是使封口大小合适的解决方案,所以我在这里做到了。

如果我正确阅读了错误,[Box<dyn Fn(u32) -> Result<u32, ()>>]: Sized则不满足,IntoParallelIterator这是我所追求的先决条件。常规into_iter()工作正常,因此 Rayon 设置了一些额外的限制。我预计人造丝会有更多的限制,但我认为这将是关于Send

我知道在这个最小的例子中我可以使用fn(...)类型而不是Fn(...)类型,因为它们不捕获任何值,但我的真实代码当然会捕获引用。

我正在使用 Rayon 为一个使用 minimax 风格的小游戏编写 AI,其中我有一个供 AI 尝试的事物列表,然后我在每件事之后观察得分。我希望这个递归调用堆栈的顶层在许多线程中启动顶层,但每个线程应该是顺序的。

4

0 回答 0