Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
782 views
in Technique[技术] by (71.8m points)

rust - Cannot move out of value which is behind a shared reference when unwrapping

This is the code I am trying to execute:

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)

I get the following error in previous versions of 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

And in more modern versions:

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()`

I see there is already a lot of documentation about borrow checker issues, but after reading it, I still can't figure out the problem.

Why is this an error and how do I solve it?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Option::unwrap() consumes the option, that is, it accepts the option by value. However, you don't have a value, you only have a reference to it. That's what the error is about.

Your code should idiomatically be written like this:

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)

Or you can use Option combinators like Option::as_ref or Option::as_mut paired with Option::map_or, as Shepmaster has suggested:

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

This code uses the fact that i32 is automatically copyable. If the type inside the Box weren't Copy, then you wouldn't be able to obtain the inner value by value at all - you would only be able to clone it or to return a reference, for example, like here:

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

Since you only have an immutable reference to the option, you can only return an immutable reference to its contents. Rust is smart enough to promote the literal 0 into a static value to keep in order to be able to return it in case of absence of the input value.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...