【问题标题】:Variable is moved to closure even when it is not executed变量即使没有被执行也会被移到闭包
【发布时间】:2021-07-18 18:39:23
【问题描述】:

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

这里有一个例子来演示:

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,但这有点违背了目的。是否有另一种更“惯用”的方式来做到这一点?

【问题讨论】:

    标签: rust closures ownership


    【解决方案1】:

    要拥有一个可以以“动态检查”方式移出的变量,可以将值包装在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&lt;String&gt;,因为该值可能已经被使用。)

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

    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)?;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 2023-01-08
      • 2012-04-15
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      • 2016-07-02
      • 2017-10-19
      相关资源
      最近更新 更多