Hello. I recently started learning Rust and I am comming from C++ and the borrow checker so far has been incredibly difficult for me to adjust to.
I decided to write a Graph based library to get some Rust experience and build a mental model about how things work (As graphs generally contain a lot of programming pitfalls).
This is my implementation
It basically fails at
let mut e1_view = get_connections(&mut graph, e1);
// let mut entry_view = get_connections(&mut graph, entry);
{
let immutabe_graph = &graph;
It considers get_connections as an mutable borrow. I would expect that it would understand that the mutable reference is dropped inside the get_connections. It is only used to initialize the EdgeView object which takes a mutable split from the Graphs vector.
It doesn't hold a reference to the Graph itself so I don't know why this error is happening.
here you are saying that you are mutably borrowing from Graph - not one of its fields. The function declaration is decisive, not what's in the function body.
// Value check
let mut e1_view = get_connections(&mut graph, e1);
// let mut entry_view = get_connections(&mut graph, entry);
{
//
for i in e1_view.iter(){
print!("{} ", *get(&graph, i));
}
}
Giving still the error:
error[E0502]: cannot borrow `graph` as immutable because it is also borrowed as mutable
--> src\tests\tree_test.rs:45:32
|
40 | let mut e1_view = get_connections(&mut graph, e1);
| ---------- mutable borrow occurs here
...
44 | for i in e1_view.iter(){
| -------------- mutable borrow later used here
45 | print!("{} ", *get(&graph, i));
| ^^^^^^ immutable borrow occurs here
I am uterrly confused now because, yes I understand that previously, with the lifetime parameter of 'a I basically told the borrow checker that the graph shall last as long as EdgeView (Which was a mistake), but now there is nothing like it and the graph is used only within the create_connection function and the borrow, as I understand it now, should end when the function returns.
Yes, the graph will stay alive until the function ends. But in Rust you cannot have an immutable borrow and a mutable borrow to the same object. The error message is saying this, take another look at it and be sure to read about this topic in the Rust book.
Why does get_connections have a &mut self param, does it need to mutate the graph? If not, change it to &self. Then you will have two immutable borrows at the same time in this function, which is allowed.
If you sometimes need a mutable view and other times you need an immutable view, create two functions: get_connections and get_connections_mut. This is common in Rust.
the EdgeView needs to hold a reference to the slice.
Is there some rust mechanism that allows me to specify whether EdgeView should the internal reference as mutable or immutable:
Actually, I keep thinking---While what you propose would fix the issue, I still don't understand why it is happening.
You are saying that You can't have mutable as well as immutable borrow at the same time.
That is clear to me, but I don't understand why does the mutable borrow still exist after:
let mut e1_view = get_connections(&mut graph, e1);
The borrow should end at function return as it is closed within that scope... After hours of googling I can't seem to find an answer anywhere, and in the rust docs, there are trivial oversimplified cases where the errors are obvious...They don't really give me an insight into this issue here
The Graph is borrowed until the lifetime 'a ends, and it cannot end until the EdgeView<'a> is dropped.
Elided lifetimes in named types are often confusing because there's no syntactic cue that a lifetime is involved, like the & symbol usually provides. You can add #![deny(elided_lifetimes_in_paths)] to require yourself to always write EdgeView<'a> or EdgeView<'_> to remind yourself that a lifetime exists at that point.
I am using this to mostly learn and it is an inaccurate outline of what I want. I use the View internally in the graph functions to access to edges and write to them.
Outside it should be read only. As mentioned previously, I will change this and it should erase the error.
But right now I am more focused on the fact that the error is comming up, because currently with my mental model and the understanding, it shouldn't happen