Variable used after move in lambda
use std::fmt::Error;
#[derive(Debug)]
struct ErrorStruct {}
struct SuccessStruct {
number: i8
}
struct Something {}
impl Something {
fn do_something(&self) -> Result<i8, Error> {
Ok(1)
}
fn into_err_struct(self) -> ErrorStruct {
ErrorStruct { }
}
fn into_success_struct(self, number: i8) -> SuccessStruct {
SuccessStruct { number }
}
}
fn do_the_thing() -> Result<SuccessStruct, ErrorStruct> {
let sth = Something{};
sth.do_something().map_err(|_| sth.into_err_struct())
.map(|number| sth.into_success_struct(number))
}
In this case we have a variable which we want to convert into different types depending on success or error.
For a human, it’s obvious that into_err_struct
and into_success_struct
are mutually exclusive, but rust will give the following error:
fn do_the_thing() -> Result<SuccessStruct, ErrorStruct> {
let sth = Something{}; // move occurs because `sth` has type `Something`, which does not implement the `Copy` trait
sth.do_something().map_err(|_| sth.into_err_struct()) // variable moved due to use in closure
.map(|number| sth.into_success_struct(number)) // use occurs due to use in closure
}
It seems that in order to make rustc understand the flow, you need to switch to using match and early return.
fn do_the_thing() -> Result<SuccessStruct, ErrorStruct> {
let sth = Something{};
let number = match sth.do_something() {
Ok(number) => number,
Err(_) => return Err(sth.into_err_struct()),
};
Ok(sth.into_success_struct(number))
}
In this case we can slim it down a bit, but that might not be applicable in all cases
fn do_the_thing() -> Result<SuccessStruct, ErrorStruct> {
let sth = Something{};
match sth.do_something() {
Ok(number) => Ok(sth.into_success_struct(number)),
Err(_) => Err(sth.into_err_struct()),
}
}
To sum it up, it seems like rust requires use of match
for branching paths who both move a variable.