为什么map和map_err捕获相同的变量?

two*_*rec 1 rust rust-actix

我正在建立一个链式的未来

ActorFuture<Item = Vec<String>, Error = Vec<String>, Actor = Self>
Run Code Online (Sandbox Code Playgroud)

成功时,它将包含链接的所有期货的字符串输出向量.and_then.在第一次错误处理将停止,我想返回成功的期货输出和最终(失败)未来错误.我想使用相同的向量来处理两个路径:ok和err.但编译器抱怨:

242 |                             .map(|o| {v.push(o); v})
    |                                  --- value moved (into closure) here
243 |                             .map_err(|e| {v.push(format!("{}", e)); v})
    |                                           ^ value captured here after move
Run Code Online (Sandbox Code Playgroud)

这是为什么?是否有可能走两个mapmap_err一次?这应该永远不会发生在我的理解中.

一个例子:

#[test]
fn test_map_and_map_err() {
    let mut v = Vec::new();
    Ok("foo".to_string())
        .map(|i| { v.push(i); v })
        .map_err(|e: String| { v.push(e); v });
}
Run Code Online (Sandbox Code Playgroud)
error[E0382]: capture of moved value: `v`
 --> src/lib.rs:6:32
  |
5 |         .map(|i| { v.push(i); v })
  |              --- value moved (into closure) here
6 |         .map_err(|e: String| { v.push(e); v });
  |                                ^ value captured here after move
  |
  = note: move occurs because `v` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

DK.*_*DK. 5

编译器不知道倒闭传递给mapmap_err相互排斥.即使它确实如此,它也无法构造两个拥有相同值的闭包.

您需要使用对编译器"透明"的构造,例如match:

#[test]
fn test_map_and_map_err() {
    let mut v = Vec::new();
    let r = Ok("foo".to_string())
        .map(|i| v.push(i))
        .map_err(|e: String| v.push(e));
    match r {
        Ok(()) => Ok(v),
        Err(()) => Err(v),
    };
}
Run Code Online (Sandbox Code Playgroud)

或者你可以改为交换价值:

#[test]
fn test_map_and_map_err() {
    use std::mem;
    let mut v = Vec::new();
    Ok("foo".to_string())
        .map(|i| {
            v.push(i);
            mem::replace(&mut v, vec![])
        }).map_err(|e: String| {
            v.push(e);
            mem::replace(&mut v, vec![])
        });
}
Run Code Online (Sandbox Code Playgroud)