变量被移动到闭包,即使它没有被执行



我有一个函数只能返回一个错误,所以我想创建一次,并在需要时返回该实例。

下面是一个示例:

fn foo() -> Result<(), String> {
let err = String::from("error message");
let a = function_that_returns_an_option().ok_or_else(|| err)?;
let b = function_that_returns_another_option().ok_or_else(|| err)?;
// ...do something with a and b...
Ok(())
}

这导致以下编译错误:

error[E0382]: use of moved value: `err`
--> src/main.rs:12:61
|
10 |     let err = String::from("error message");
|         --- move occurs because `err` has type `String`, which does not implement the `Copy` trait
11 |     let a = function_that_returns_an_option().ok_or_else(|| err)?;
|                                                           -- --- variable moved due to use in closure
|                                                           |
|                                                           value moved into closure here
12 |     let b = function_that_returns_another_option().ok_or_else(|| err)?;
|                                                                ^^ --- use occurs due to use in closure
|                                                                |
|                                                                value used here after move

我认为移动是懒惰的,但如果我理解正确的话,即使闭包没有执行,err也会移动到第一个闭包,因此它不能在第二个闭包中使用(或者编译器不知道这一点,为了安全起见拒绝了它?(。我可以用err.clone()替换闭包中的err,但这有点违背目的。是否还有另一个";惯用的";怎么做?

要有一个可以"动态检查"方式移出的变量,可以将值包装在Option中并使用Option::take:

let mut err = Some(String::from("error message"));
let a = function_that_returns_an_option().ok_or_else(|| err.take().unwrap())?;
let b = function_that_returns_another_option().ok_or_else(|| err.take().unwrap())?;

(需要.unwrap(),因为.take()返回Option<String>,因为该值可能已经被取了。(

然而,无论如何,这并不是错误处理的最佳选项,因为即使函数成功,也要分配错误字符串。有一种简单的方法可以避免这种情况,并进一步简化代码:将分配放入闭包中,并重用闭包而不是消息值:

let err = || String::from("error message");
let a = function_that_returns_an_option().ok_or_else(err)?;
let b = function_that_returns_another_option().ok_or_else(err)?;

最新更新