-1

I have a very simple piece of code that I cannot get to compile:

struct X;

struct A {
    field: Option<Box<X>>,
}

impl A {
    pub fn get_field(&self) -> Option<&X> {
        return self.field.map(|value| &*value);
    }
}
error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:9:16
  |
9 |         return self.field.map(|value| &*value);
  |                ^^^^ cannot move out of borrowed content

error[E0597]: `*value` does not live long enough
 --> src/lib.rs:9:40
  |
9 |         return self.field.map(|value| &*value);
  |                                        ^^^^^-
  |                                        |    |
  |                                        |    borrowed value only lives until here
  |                                        borrowed value does not live long enough
  |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 8:5...
 --> src/lib.rs:8:5
  |
8 | /     pub fn get_field(&self) -> Option<&X> {
9 | |         return self.field.map(|value| &*value);
10| |     }
  | |_____^

I don't really understand why this doesn't work.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Max
  • 15,157
  • 17
  • 82
  • 127

1 Answers1

6

I don't really understand why this doesn't work.

Your code defined a struct A that may or may not hold a X in the heap (not in the stack).

In the method get_field you were given a reference to the struct, but you want to get a reference to the inner X, if possible.

The above are concluded only by looking at the function signatures and struct definition of A.

Looking into the function body, self.field is of type Option<_>, and map is its method. Look at the documentation for Option::map:

pub fn map<U, F>(self, f: F) -> Option<U> 
where
  F: FnOnce(T) -> U,

Maps an Option<T> to Option<U> by applying a function to a contained value.

It accepts a closure that can only run once, accepts a Box<X> in your case, then according to your function return type it should return &X. It looks like a perfect match at first glance since if value: Box<X> then *value: X and &*value: &X, but it does not compile! What's wrong?

If you look more carefully at the signature of map you see it has 2 parameters, not one. The first parameter is the "method receiver" self and its type is Self.

In Rust, this means this call will need to consume the method receiver; the object you used to call the method would be no longer valid after this call.

However, your get_field method is not allowed to remove the method receiver self.field: self is only a reference to A, so self.field is also just a reference . You then cannot call map to consume self.field.

The solution, is to use as_ref:

pub fn as_ref(&self) -> Option<&T>

Converts from Option<T> to Option<&T>.

Although it says converts from Option<T>, but from the signature you can see it accepts &Option<T>, so it just moves the outside & inside. Now you can use map.

 pub fn get_field(&self) -> Option<&X> {
    return self.field.as_ref().map(|value| &*value);
 }

Now it works.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Earth Engine
  • 10,048
  • 5
  • 48
  • 78