#satisfy the borrow checker in this piece of code

47 messages · Page 1 of 1 (latest)

hoary edge
#
fn remove_selected(players: &mut Vec<Player>, ids: Vec<String>) {
    let selected_players = select_players(players, ids); // takes a reference
    let selected_players = selected_players
        .into_iter()
        .map(|p| p.name.as_str())
        .enumerate()
        .collect::<Vec<(usize, &str)>>();
    // sort and reverse with pos as key
    for (pos, _) in selected_players {
        players.remove(pos);
    }
}
error[E0502]: cannot borrow `*players` as mutable because it is also borrowed as immutable
   --> src\main.rs:309:21
    |
300 |             let selected_players = select_players(players, ids)?;
    |                                                   ------- immutable borrow occurs here
...
308 |                 for (pos, _) in selected_players {
    |                                 ------------------------ immutable borrow later used here
309 |                     players.remove(pos);
    |                     ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

I am trying to remove some indices from a mutable vector, however, I cannot find a way to work around the borrow checker. I really do not need the selected_players to be a view into players, so it can be some seperate, cloned values, but even if I try to clone selected_players or the string slices inside of it, it still doesn't let me remove those positions. I do need those string slices, because I want to print the names of the items that were removed in the terminal.

fervent portal
#

your indices will be off by one the first iteration of the loop, off by two the second, and so on

#

what's the type of select_players?

#

if it returns &Player then it's holding references to the contents of players, you can't remove them from the Vec because that would make the references invalid

warped vapor
swift ledge
#

doesn't seem like it'll work

#

removing with a given index will shift the indices of everything else being removed

#

oh someone already said that

warped vapor
#

Assuming this works (I wrote it on a phone), it should do all in-place without issues

let mut pos = 0;
let mut to_remove = selected.into_iter().peekable();
players.retain(|_| {
  let current = pos;
  pos += 1;
  let Some(rem) = to_remove.peek() else { return true };
  if rem != current { return true }
  to_remove.next();
  false
})
swift ledge
#

any reason not to just use a filter

#

oh yeah, retain

#

that also works

warped vapor
#

Filter might honestly be easier to read, this isn't exceedingly pretty

swift ledge
#

avoids a heap allocation

warped vapor
#

That it does

swift ledge
#

not sure it'll work either though

#

you're peeking the positions one by one and removing them based on that

#

I guess if the positions are sorted it'll work

swift ledge
warped vapor
#

You could sort them, but I agree the choice to use a vec at all is beginning to be sus

swift ledge
#
fn remove_selected(entries: &mut Vec<Player>, ids: HashSet<String>) {
  entries.retain(|p| !ids.contains(&p.name));
}```
#

might even want to do a HashSet<&str>, since I doubt they need to be owned strings

#

actually, how are you storing players? maybe they shouldn't even be in a list in the first place, and you can just keep them in a map like HashMap<String, Player>

#

could even do Arc<str> and store it as a HashMap<Arc<str>, Player> and store it as Arc<str> in Player too so you're not doubling up on allocations

hoary edge
hoary edge
#

Sorry, ill respond to your help in a while. Something came up

hoary edge
swift ledge
#

mm

#

just be careful passing around indices to a list that can be removed from

hoary edge
#

It's an audio looper

warped vapor
warped vapor
#

And also faster, but that's secondary

swift ledge
#

just think about the microseconds you'll save!

hoary edge
#

Are arc str easier than string slices?

hoary edge
swift ledge
#

I see

outer valve
# hoary edge Are arc str easier than string slices?

If you're storing them often, probably. It turns a struct with a lifetime into a struct without one, while retaining all of the performance benefits of using a string slice over an owned string (minus the cost of incrementing an atomic usize)

hoary edge
hoary edge
#

I have solved it by using unsafe:

select_players(unsafe { &*(players as *const Vec<Player>) }, ids)?

I just have to print the names before I remove the players

warped vapor
#

Unsafe is best reserved for safely encapsulated modules, not as a workaround in otherwise safe code

#

I'm not your code reviewer, though, so... Go ahead at your own risk, I guess