Rust can't get out of dereference pointer

I am trying to run this code:

impl FibHeap {
fn insert(&mut self, key: int) -> () {
    let new_node = Some(box create_node(key, None, None));

        match self.min{
            Some(ref mut t) => t.right = new_node,
            None => (),
        };
        println!("{}",get_right(self.min));
    }
}
fn get_right(e: Option<Box<Node>>) -> Option<Box<Node>> {
    match e {
        Some(t) => t.right,
        None => None,
    }
}

      

And get the error

error: cannot move out of dereference of `&mut`-pointer
println!("{}",get_right(self.min));
              ^

      

I don't understand why I am getting this problem and what I should be using to avoid the problem.

+3


source to share


1 answer


Your problem is what get_right()

accepts Option<Box<Node>>

, while it should actually accept Option<&Node>

and return Option<&Node>

. The calling site should also be modified accordingly.

Here's an explanation. Box<T>

is a heap-allocated field. It obeys value semantics (that is, it behaves like a plain T

, except that it is associated with a destructor, so it always moves, never copied). Therefore, passing only Box<T>

to a function means giving up ownership of the value and moving it into a function. However, this is not what you really want and cannot here. The function get_right()

only asks for an existing structure, so it doesn't need ownership. And if ownership is not required, then links are the answer. Moreover, it is simply not possible to move self.min

into a function, because it self.min

is accessible viaself

which is a borrowed pointer. However, you cannot get out of the borrowed data, this is one of the main safety guarantees provided by the compiler.

Change the definition get_right()

to the following:

fn get_right(e: Option<&Node>) -> Option<&Node> {
    e.and_then(|n| n.right.as_ref().map(|r| &**r))
}

      

Then the call println!()

should be replaced with:

println!("{}", get_right(self.min.map(|r| &**r))

      



Here's what's going on here. To get Option<&Node>

from Option<Box<Node>>

, you need to apply a "transform" to the interior of the original Option

. For this there is a method called map()

. However, it map()

takes its target by value, which means moving Box<Node>

into a closure. However, we only want to take Node

, so we first need to go from Option<Box<Node>>

to Option<&Box<Node>>

in order for it to map()

work.

Option<T>

has a method as_ref()

that takes its target by reference and returns a Option<&T>

possible reference to the internals of the option. In our case, it will be Option<&Box<Node>>

. This value can now be safely map()

changed since it contains a link and the link can be moved freely without affecting the original value.

So then map(|r| &**r)

is a conversion from Option<&Box<Node>>

to Option<&Node>

. The close argument is applied to the inner elements of the option, if present, otherwise None

simply passed. &**r

should be read inside out: &(*(*r))

i.e. first we seek &Box<Node>

, we get Box<Node>

, then we play the latter, get simple Node

, and then take a link to it, finally get &Node

. Since these link / dereference operations are matched, there is no movement / copying. Thus, we have an optional link to Node

, Option<&Node>

.

You can see similar things happening in the function get_right()

. However, there is also a new method called and_then()

. This is equivalent to what you wrote in get_right()

originally: if its target is None

, it returns None

, otherwise it returns the result Option

-direct closure passed as an argument:

fn and_then<U>(self, f: |T| -> Option<U>) -> Option<U> {
    match self {
        Some(e) => f(e),
        None => None
    }
}

      

I highly recommend reading the official guide , which explains what ownership and borrowing are and how to use them, because they are the very foundation of the Rust language, and it's very important to understand them in order to be productive with Rust.

+10


source







All Articles