Vector in place, why borrow has not ended?


#1

So I have a Vec<Option<Node>> field in my struct called nodes. Than I have the following method:

fn get_mut_node(&mut self, index: usize) -> Result<&mut ComputeNode, String>{
		try!(self.nodes.get_mut(index).ok_or("Out of bounds"))
                .as_mut().ok_or(format!("The node {} is None", index))
}

Now I understand that for the borrow checker this means that I’m taking *self. My question why this does not compile:

let node = try!(self.get_mut_node(gradient));
/* Something or noting */
let node = try!(self.get_mut_node(2));

But than this does:

let _ = try!(self.get_mut_node(gradient));
/* Something or noting */
let node = try!(self.get_mut_node(2));

Understandably in both cases when I hit the last line, I’m releasing node or _ and the borrow of self should end, no? Can someone help me understand this?


#2

You can’t have two mutable borrow to something at the same time. _ means that the value should be thrown out into the void, so that’s why the second example works. The first example is a nice demonstration of how variables works in Rust. The thing is that you are not changing the value of node. You are instead reassigning the name node to an other variable, while still keeping the old one in the background. What you can do if you really want to release node is to scope it, drop it or overwrite it.

Scoping:

{
    let node = try!(self.get_mut_node(gradient));
}

let node = try!(self.get_mut_node(2));

Dropping:

let node = try!(self.get_mut_node(gradient));
std::mem::drop(node);
let node = try!(self.get_mut_node(2));

Overwriting:

let mut node = try!(self.get_mut_node(gradient));
node = try!(self.get_mut_node(2));

Note that I have not tested any of these, but the scope and the drop should work.


#3

Thanks, I did not know that the compiler does not look of when the variable is used lastly and drop it there automatically (my presumption and why I thought this works). Thanks for the answer. Unfortunately for some reason the drop and overwriting don’t work, but scoping does, so that’s fine for me!


#4

Yeah, they are dropped at the end of the scope, in the reverse order of creation.


#5

Having the borrow checker already and knowing the ownership of each variable, does not that allow Rust, to be able to drop variables on their last usage, rather than when they go out of scope?


#6

Possibly, maybe, probably. It may have some consequences regarding destructors and such, but I don’t know. I’m sure they considered it.


#7

See https://github.com/rust-lang/rfcs/issues/811 and the isuses linked from it


#8

The idea of allowing the compiler to drop any variable once it was no longer borrowed or used was discussed in RFC 239.