I don't understand why Vec::peek_mut is needed

What is the rationale for Vec::peek_mut ?

It seems to me that last_mut( available via Deref trait) has the same functionality ( it returns a mut ref to the last element, or None if the Vec is empty ).

What am I missing?

[ Well it actually returns a PeekMut struct, I guess it has something to do with that, and the pop method in that, but I am still having trouble seeing why it is useful ]

From the linked issue it lets you remove the item you're peeking at if you so desire. You can write x.peek_mut().unwrap().pop() which you can't do with last_mut.

EDIT: you can't do that, but you can write PeekMut::pop(x.peek_mut().unwrap()) as corrected below ... I hope!

I think that the docs are a bit too sparse on this. Vec::peek_mut returns a PeekMut, which is a mutable view on the underlying Vec, not a mutable reference.
It also exposes an associated function pop(), which allows to remove the peeked element from the Vec.
This allows for something like:

#![feature(vec_peek_mut)]

use std::vec::PeekMut;

fn main() {
    let mut elements = vec![123];

    if let Some(peeked_mut) = elements.peek_mut() {
        if *peeked_mut == 123 {
            let removed = PeekMut::pop(peeked_mut);
            dbg!(removed);
        }
    }
}

Alas, you cannot do this, because pop() is not a method, i.e. does not take self.

3 Likes

Thanks for the correction.

It really seems like modifying a container is not in the spirit of "peeking" and this terminology is not great.

The docs and example should definitely be improved before stabilization. This method isn’t useful unless you want to conditionally pop from the Vec; if you just want to modify the last element if it exists, there’s already last_mut as you said.

3 Likes

It seems to me the straight-forward way to do that is something like ( pseudo-code )

let flag = { have a look at the last element, figure out if it should be popped };
if flag { pop the last element }

“flag” can of course be eliminated.

I don’t see the advantage in having peek_mut.

From the point of view of code readability, most people coming across it will not know what it is, will need to consult documentation, and go through the cycle of confusion I just went through.

Me neither. :slight_smile:

1 Like

pop on Vec returns an Option. peek_mut removes the need for that. that's the purpose of peek_mut.

3 Likes

Yeah, not only does peek_mut mean you only test is_empty once (in effect), it borrows the Vec mutably so the borrow checker will forbid you from accidentally modifying the vector between the test and the pop.

We already have pop_if for that.

It's not quite the same thing though. There are three states: empty vector, last element doesn't satisfy predicate, last element satisfies predicate. pop_if returning None doesn't distinguish between the first two. This seems analogous to the Entry API.

1 Like

In that sense peek_mut appears to supersede both pop_if and last_mut, as the latter are trivially implementable in terms of peek_mut.

I think it's a little tricky to do last_mut. Wouldn't it have to drop the PeekMut object that it would be borrowing from via DerefMut?

Ok, I guess that is the answer, although of course result of the pop can be unwrapped, or matched etc. as normal. So the answer seems to be it isn’t really needed, but it has some utility. I am not entirely convinced it is a good idea though, but I guess that is a matter of taste.

1 Like