Lifetimes for things passed to `map_err`

This does not compile, but I don't see why not:

fn work(foo: Vec<usize>) -> Result<Vec<usize>, Vec<usize>> {
    Err(()).map_err(|_| foo)?;

    Ok(foo)
}

It claims foo has been moved:

error[E0382]: use of moved value: `foo`
 --> src/main.rs:5:8
  |
2 | fn work(foo: Vec<usize>) -> Result<Vec<usize>, Vec<usize>> {
  |         --- move occurs because `foo` has type `Vec<usize>`, which does not implement the `Copy` trait
3 |     Err(()).map_err(|_| foo)?;
  |                     --- --- variable moved due to use in closure
  |                     |
  |                     value moved into closure here
4 |
5 |     Ok(foo)
  |        ^^^ value used here after move

I thought the borrow checker was smart enough to see that only one of two "ownership transfer paths" can occur here. Why is it insisting that foo has been moved? I really don't want to clone() in this case.

The function always calls map_err, and always passes it a closure that owns foo, so foo is always moved whether or not the ? then causes an early return.

If the body of map_err were inlined into your function, and your closure inlined into that, then maybe the compiler could see that the two moves of foo were on mutually exclusive paths. But this isn’t how the compiler works: Checking a function body is local and does not depend on other function bodies. (This has important benefits; for example, changes to the body of a library function won’t break callers of that function.)

Instead, you’ll need to do the “inlining” manually by using a control-flow expression like if or match:

fn work(foo: Vec<usize>) -> Result<Vec<usize>, Vec<usize>> {
    let result = get_result();
    if let Err(_) = result {
        return Err(foo);
    }
    Ok(foo)
}
7 Likes

could you provide some more details into what you are trying to do? Why do you need to return the vector in both an error and a non-error case? Or is this just for educational purposes?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.