【问题标题】:Cannot move out of value which is behind a shared reference when unwrapping展开时无法移出共享引用后面的值
【发布时间】:2015-11-27 02:32:49
【问题描述】:

这是我要执行的代码:

fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
    if arg1.is_none() {
        return 0;
    }
    let integer = arg1.unwrap();
    *integer
}

fn main() {
    let integer = 42;
    my_fn(&Some(Box::new(integer)));
}

(on the Rust playground)

我在以前版本的 Rust 中收到以下错误:

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:5:19
  |
5 |     let integer = arg1.unwrap();
  |                   ^^^^ cannot move out of borrowed content

在更现代的版本中:

error[E0507]: cannot move out of `*arg1` which is behind a shared reference
 --> src/main.rs:5:19
  |
5 |     let integer = arg1.unwrap();
  |                   ^^^^
  |                   |
  |                   move occurs because `*arg1` has type `std::option::Option<std::boxed::Box<i32>>`, which does not implement the `Copy` trait
  |                   help: consider borrowing the `Option`'s content: `arg1.as_ref()`

我看到已经有很多关于借用检查器问题的文档,但是阅读后我仍然无法弄清楚问题所在。

为什么这是一个错误,我该如何解决?

【问题讨论】:

    标签: rust borrow-checker


    【解决方案1】:

    Option::unwrap() 消费选项,即按值接受选项。但是,您没有价值,您只有对它的引用。这就是错误所在。

    你的代码应该习惯性地写成这样:

    fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
        match arg1 {
            Some(b) => **b,
            None => 0,
        }
    }
    
    fn main() {
        let integer = 42;
        my_fn(&Some(Box::new(integer)));
    }
    

    (on the Rust playground)

    或者您可以使用 Option 组合符,如 Option::as_refOption::as_mutOption::map_or 配对,正如 Shepmaster 建议的那样:

    fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
        arg1.as_ref().map_or(0, |n| **n)
    }
    

    此代码使用i32 可自动复制的事实。如果Box 中的类型不是Copy,那么您根本无法按值获取内部值 - 您只能克隆它或返回引用,例如这里:

    fn my_fn2(arg1: &Option<Box<i32>>) -> &i32 {
        arg1.as_ref().map_or(&0, |n| n)
    }
    

    由于您只有对该选项的不可变引用,因此您只能返回对其内容的不可变引用。 Rust 足够聪明,可以将文字 0 提升为静态值以保留,以便在没有输入值的情况下能够返回它。

    【讨论】:

    • 如果我想获得对盒子内 i32 的引用(假设我想修改它并让程序的另一部分看到更改后的值)怎么办?
    • FWIW,我会写成arg1.as_ref().map(|x| **x).unwrap_or(0)
    • @Moebius,我已经用一个带有参考的示例更新了我的答案,但是,我并不完全理解你对修改值的意思。举个例子会有帮助,但无论如何它可能值得另一个问题。
    • @VladimirMatveev 没有特殊用例,我只是出于好奇而问。感谢您的解决方案!
    【解决方案2】:

    由于 Rust 1.40 有 Option::as_deref,所以现在你可以这样做了:

    fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
        *arg1.as_deref().unwrap_or(&0)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 2020-02-12
      • 1970-01-01
      • 2015-03-25
      • 1970-01-01
      • 2021-12-02
      相关资源
      最近更新 更多