How to take the first element of a BTreeSet without clone [duplicate] - rust

This question already has answers here:
Getting first member of a BTreeSet
(2 answers)
Closed 2 years ago.
I need to implement a function similar to the unstable BTreeSet::pop_first().
It is not a duplicate of Getting first member of a BTreeSet, since I ask for a way get the first element of a BTreeSet without making a copy.
fn pop<O:Ord>(set: &mut std::collections::BTreeSet<O>) -> O
Based on a previous question (Getting first member of a BTreeSet), I get a compiler error about a mutable use after an inmutable one:
pub fn pop<O:Ord>(set: &mut std::collections::BTreeSet<O>) -> O {
let n = {
let mut start_iter = set.iter();
start_iter.next().unwrap()
};
set.take(n).unwrap()
}
error[E0502]: cannot borrow `*set` as mutable because it is also borrowed as immutable
--> src/main.rs:493:5
|
489 | let mut start_iter = set.iter();
| --- immutable borrow occurs here
...
493 | set.take(n).unwrap()
| ^^^^----^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
If I replace set.iter() with set.iter().clone() the code works, but I would like to not make copies of the elements of the set because it will be a costly operation.
How can I implement such a pop function?
rustc version 1.41.0

It is not possible to implement that function like you ask without access to the internals of BTreeSet: The elements of the iterator are borrowed from the set, so n is borrowed from the set as well. While you have borrowed something from the set, you cannot modify it.
You could:
Use clone()/cloned(), like you mentioned. If you were worried it would clone all elements in the iterator when calling pop_first(), that's not the case. It would clone only the one element since iterators are lazy.
Keep both a BinaryHeap and a HashSet of your elements. Before inserting an element into the BinaryHeap, check whether it is already in the HashSet.
Find/implement an extended BTreeSet from scratch that has this functionality.

Related

Why the order of computing operands is direct and not reverse? (Swapping in a Vec without a local variable) [duplicate]

This question already has an answer here:
Why is indexing a mutable vector based on its len() considered simultaneous borrowing?
(1 answer)
Closed 2 months ago.
This post was edited and submitted for review last month and failed to reopen the post:
Original close reason(s) were not resolved
All I wanna do is to swap the first and the last element in Vec.
So I wrote this:
// getting a vector of integers from stdin:
let mut ranks = std::io::stdin()
.lock()
.lines()
.next()
.unwrap()
.unwrap()
.trim()
.split_whitespace()
.map(|s| s.parse::<usize>().unwrap())
.collect::<Vec<usize>>();
// ...
// pushing something to ranks
// ...
ranks.swap(0, ranks.len() - 1); // <------ TRYING TO SWAP
And of course, it doesn't work, because
error[E0502]: cannot borrow `ranks` as immutable because it is also borrowed as mutable
--> src\main.rs:4:19
|
4 | ranks.swap(0, ranks.len() - 1);
| --------------^^^^^^^^^^^-----
| | | |
| | | immutable borrow occurs here
| | mutable borrow later used by call
| mutable borrow occurs here
|
help: try adding a local storing this argument...
--> src\main.rs:4:19
|
4 | ranks.swap(0, ranks.len() - 1);
| ^^^^^^^^^^^
help: ...and then using that local as the argument to this call
By using this piece of advice the compiler gave me, I came up with following:
let last = ranks.len() - 1;
ranks.swap(0, last);
...which looks terrible.
So the thing is: why do I need to create local variable to store vector length, if I want to pass it to the method? Well, of course because of the borrowing rules: the value of ranks will be borrowed as mutable as I call swap, so that I can't use ranks.len() anymore.
But isn't it reasonable to suppose that the values of parameters will be calculated before the method starts to do anything and before it somehow can change the content of vector or it's length?
Basically, the order of computing parameters of a function is straight in Rust, which creates many obsticles for writing clean code for me. So I would like to ask, why the order is chosen to be straight? Cause if it was reverse, things would be much easier to express. For instance, the above piece of code could be rewritten as:
ranks.swap(0, ranks.len() - 1);
...which (I think you would agree) is much more readable and cleaner.
Also, it is strange that the similar in the sense of borrowing code compiles succesfully:
let mut vec = vec![1, 2, 3]; // creating vector
vec.push(*vec.last().unwrap()); // DOUBLE BORROWING HERE!!!
// ^ ^
// | |
// | ----- immutable
// ----- mutable
println!("{:?}", vec);
So what the hell is going on? Double standarts, aren't they?
I would like to know the answer. Thank you for explanation.
but isn't it reasonable to suppose that the values of parameters will be calculated before the method starts to do anything and before it somehow can change the content of vector?
...are you sure?
Evaluation order of operands
The following list of expressions all evaluate their operands the same way, as described after the list. Other expressions either don't take operands or evaluate them conditionally as described on their respective pages.
...
Call expression
Method call expression
...
The operands of these expressions are evaluated prior to applying the effects of the expression. Expressions taking multiple operands are evaluated left to right as written in the source code.
So, self is evaluated before ranks.len() - 1. And self is actually &mut self because of auto-ref. So you first take a mutable reference to the vector, then call len() on it - that requires a borrowing it - while it is already borrowed mutably!
Now, this sometimes work (for example, if you would call push() instead of swap()). But this works by magic (called two-phase borrows that splits borrowing into borrowing and activating the reference), and this magic doesn't work here. I think the reason is that swap() is defined for slices and not Vec and thus we need to go through Deref - but I'm not totally sure.

Why can't I use PineMap to store a referential cons-list? Getting "still borrowed" error even after end of main [duplicate]

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed last month.
Why does this code:
#[derive(Eq, PartialEq, Ord, PartialOrd)]
enum List<'a> {
Cons(isize, &'a List<'a>),
Nil,
}
fn main() {
use List::*;
use pinus::{prelude::*, sync::PineMap};
let table = PineMap::new();
table.insert(Nil, Nil);
let nil = table.get(&Nil).unwrap();
table.insert(Cons(1, nil), Cons(1, nil));
}
cause this error:
error[E0597]: `table` does not live long enough
--> src/main.rs:12:15
|
12 | let nil = table.get(&Nil).unwrap();
| ^^^^^^^^^^^^^^^ borrowed value does not live long enough
13 | table.insert(Cons(1, nil), Cons(1, nil));
14 | }
| -
| |
| `table` dropped here while still borrowed
| borrow might be used here, when `table` is dropped and runs the `Drop` code for type `PineMap`
I'm using a pinus::sync::PineMap to try to make sure that all references to equivalent instances of List are actually references of the same object in memory. I thought a way to do this would be to have a table mapping List keys to a table-owned instance of List, and I'm trying out PineMap for it because its insert will not move its items in memory (its insert borrows &self not &mut self too) so references to its List values will stay valid, and I can build self-referential items.
Why is table still considered to be borrowed at the end of its scope in my code?
When you get nil out of the table and put it back into it with Cons(1, nil), the type of nil is a reference that is tied to the lifetime of the table, and thus the lifetime 'a of the Lists that you're storing are bound to the table that is storing them.
The core problem here is that this creates a self-referential struct, which introduces a myriad of problems. You wouldn't be able to call any of the mutable methods either because the table is permanently borrowing itself immutably.
The specific problem that the compiler is complaining about is that, since the elements hold a reference to the table, when its being dropped the drop logic may try to access data that is in the process of being destroyed, which is not sound.
I encourage you to read about the Drop Check in the Rustonomicon for more info, here's a guiding principle though:
For a generic type to soundly implement drop, its generics arguments must strictly outlive it.
I don't have any workarounds or solutions for you other than you can't do it this way.

"Popping" a value from a HashSet

I can't seem to find a way to pop a (random) value from a HashSet. Inspired by other code samples, I wrote the following:
my_set.iter().next().map(|i| my_set.take(i).unwrap())
I.e get an iterator on the set's values, take the first value (a reference) from it, and then run my_set.take() using the reference previously obtained, to get the value itself (not the reference) and remove it from the set.
This doesn't compile due to:
error[E0500]: closure requires unique access to `my_set` but it is already borrowed
|
32 | my_set.iter().next().map(|i| my_set.take(i).unwrap())
| ------ --- ^^^ ------ second borrow occurs due to use of `my_set` in closure
| | | |
| | | closure construction occurs here
| | first borrow later used by call
| borrow occurs here
I've tried many, many variations on this, but they all fail due to an immutable borrow then being borrowed as mutable (error 502).
Can any one recommend a way to rewrite the above?
If you're okay with cloning the item removed you can do:
let elem = set.iter().next().unwrap().clone();
set.remove(&elem);
Playground
Or with a guard against the set being empty:
if let Some(elem) = set.iter().next().cloned() {
set.remove(&elem);
}
Playground
This feels hacky, but you can use HashSet::retain with an impure function:
let mut flag = false;
my_set.retain(|_| mem::replace(&mut flag, true));
(playground)
The element removed is truly arbitrary — I ran the code on the playground a few times, and obtained different results.
As interjay mentioned in a comment, this approach iterates over the entire set just to remove one value, so the cost is generally more significant than cloning one value. Therefore, only use this workaround when the element really cannot be cloned.

How can one array contain multiple mutable references to the same object? [duplicate]

This question already has answers here:
How to represent shared mutable state?
(2 answers)
Situations where Cell or RefCell is the best choice
(3 answers)
Need holistic explanation about Rust's cell and reference counted types
(2 answers)
Closed 4 years ago.
I'm making a tile-based game with structures that span multiple tiles. Every tile under the structure has to have a mutable reference to that structure. For a structure that spans two tiles, the 2D array that represents the map has to simultaneously contain two mutable references to the structure.
I also have a list that mutably owns all my structures (for iteration)
I tried this with &mut and failed:
let mut all_structures: Vec<Box<Structure>> = Vec::new();
let mut grid: [[Vec<&mut Box<Structure>>; 4]; 4] = Default::default(); // accessed [y][x]
let mut house: Box<Structure> = Box::new(House { });
grid[1][1].push(&mut house);
grid[1][2].push(&mut house);
all_structures.push(house);
with error:
error[E0499]: cannot borrow `house` as mutable more than once at a time
--> src/main.rs:21:21
|
20 | grid[1][1].push(&mut house);
| ---------- first mutable borrow occurs here
21 | grid[1][2].push(&mut house);
| ---- ^^^^^^^^^^ second mutable borrow occurs here
| |
| first borrow later used by call
Right now this is just single threaded so nothing needs to be thread-safe
I put the code on the playground
The simplest option would be to use Rc<RefCell<Structure>> instead of Box<Structure>.
Rc<T> supports shared ownership of a value of type T, which lets you have multiple pointers to the same object with automatic lifetime management. Rc<T> is not thread-safe; you can change to using Arc instead if you later find you need thread-safety.
RefCell<T> allows you to enforce the Rust borrowing rules (that is, that there can be either one &mut borrow or any number of & borrows) at runtime rather than at compile time: this means it's OK to have multiple paths by which you could potentially mutate the same object, so long as you don't actually do so.
I've put a complete example up on the playground. Note that this uses .borrow() and .borrow_mut(), which will panic if you actually end up violating the borrowing rules (e.g., by mutably borrowing the same Structure multiple times at once).

Why does it look like a closure borrows self instead of a field of self? [duplicate]

I have a struct containing two fields and I want to modify one field (mutable borrow) using another field (immutable borrow), but I get an error from the borrow checker.
For instance, the following code:
struct Struct {
field1: Vec<i32>,
field2: Vec<i32>,
}
fn main() {
let mut strct = Struct {
field1: vec![1, 2, 3],
field2: vec![2, 3, 4],
};
strct.field1.retain(|v| !strct.field2.contains(v));
println!("{:?}", strct.field1);
}
gives the following error:
error[E0502]: cannot borrow `strct.field1` as mutable because it is also borrowed as immutable
--> src/main.rs:12:5
|
12 | strct.field1.retain(|v| !strct.field2.contains(v));
| ^^^^^^^^^^^^^------^---^^-----^^^^^^^^^^^^^^^^^^^^
| | | | |
| | | | first borrow occurs due to use of `strct` in closure
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
What are the Rust ways of updating one field using another from within a closure?
Usually the borrow checker can distinguish between the different fields of a structure, but this doesn't work within closures (lambdas).
Instead, borrow the second field outside the closure:
let field2 = &strct.field2;
strct.field1.retain(|v| !field2.contains(v));
This recent blog post shows a very useful pattern for this kind of problem:
Sometimes, when I want to be very precise, I will write closures in a stylized way that makes it crystal clear what they are capturing. Instead of writing |v| ..., I first introduce a block that creates a lot of local variables, with the final thing in the block being a move closure (move closures take ownership of the things they use, instead of borrowing them from the creator). This gives complete control over what is borrowed and how. In this case, the closure might look like:
In other words, the borrows are defined right with the closure and moved into the closure. This makes it totally clear that their purpose is to provide the closure with borrowed values. In context of the original question the pattern would look like this:
strct.field1.retain({
let field2 = &strct.field2;
move |v| !field2.contains(v)
});
A nice property of this code is that the borrow of field2 does not stick around after it is no longer used.

Resources