无法将iter()。fold(....)转换为Rayon< par_iter()。fold(....)

时间:2017-06-12 19:31:08

标签: rust

我尝试使用Rayon启动一系列顶级线程来递归调用模拟函数。该代码适用于使用频道发送&接收,因此它与多线程兼容,但无法使用par_iter()进行编译。

fn simulate(initial_board: &Board, player: Player, level: u32, start: bool) -> Option<AMove> {
...

    #[inline(always)]
    fn evaluate_move(previous: Option<AMove>, new_move: &AMove, new_score: i32, player: Player) -> AMove {
    ...
    }

... 

let accumlator = |previous: Option<AMove>, a_move: &Option<AMove>| if let Some(AMove { board: ref a_board, .. }) = *a_move {
        ...
    } else {
        previous
    };

    if start && !winning {
        the_move = moves.par_iter().fold(the_move, accumlator);
    } else {
        the_move = moves.iter().fold(the_move, accumlator);
    }

    the_move
}

我在使用par_iter()的行上遇到了编译器错误,我对如何解决这些问题感到很遗憾。

error[E0277]: the trait bound `std::option::Option<AMove>: std::ops::Fn<()>` is not satisfied
   --> src/main.rs:271:37    
    |
271 |         the_move = moves.par_iter().fold(the_move, accumlator);
    |                                     ^^^^ the trait `std::ops::Fn<()>` is not implemented for `std::option::Option<AMove>`

error[E0277]: the trait bound `std::option::Option<AMove>: std::ops::FnOnce<()>` is not satisfied
   --> src/main.rs:271:37
    |
271 |         the_move = moves.par_iter().fold(the_move, accumlator);
    |                                     ^^^^ the trait `std::ops::FnOnce<()>` is not implemented for `std::option::Option<AMove>`

error[E0308]: mismatched types
   --> src/main.rs:271:20
    |
271 |         the_move = moves.par_iter().fold(the_move, accumlator);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        expected enum `std::option::Option`, found struct `rayon::iter::Fold`
    |
    = note: expected type `std::option::Option<_>`
               found type `rayon::iter::Fold<rayon::slice::Iter<'_, std::option::Option<AMove>>, std::option::Option<_>, [closure@src/main.rs:224:22: 240:6 winning:_, level:_, player:_]>`

2 个答案:

答案 0 :(得分:2)

Rayon的fold想要一个产生一个身份元素的函数,而不是一个基本元素。在您的情况下,如果AMoveCopy + Send + Sync,则只需执行moves.par_iter().fold(|| the_move, accumlator)即可。

如果AMove不是Copy,请使用|| the_move.clone()

Rayon可能希望生成多个标识元素以并行执行不同的块,并且只在最后合并结果,这就是为什么它需要能够生成所需数量的标识元素。

检查fold&#39; s signature。此外,如果您的累加器返回与identity元素相同的类型,您可能希望使用reduce代替(请参阅链接文档以了解差异)。

另一个问题是,您不能按照您尝试的方式使用递归闭包(Rust不能这样做)。使用命名函数代替累加器。

答案 1 :(得分:0)

解决方案在于在生成的reduce上使用fold。谢谢你暗示我。我终于在Rayon演示中找到了一个例子,为我的案例铺平了解决方案。以下是未来参考的方式。

moves.par_iter()
     .fold(|| None, accumlator)
     .reduce(|| None, |previous: Option<AMove>, a_move: Option<AMove>| {
        if let Some(a_move) = a_move {
            Some(select_move(&previous, &a_move, player))
        } else {
            previous
        }
    })

最令人费解的错误是最初出现的错误,因为我使用的是fold(a,b)而不是fold(|| a,b),它抱怨FnFnOnce并让我无能为力。< / p>