Hmm. I think you misunderstood the problem (possibly I over-simplified the toy version). In your "works" function, you're evicting an already-evicted entry? What? Also, you're still doing two map lookups, so you've (a) used my two-lookup solution (b) violated encapsulation by exposing the evict function and (c) returned a weird error to the caller... you're telling the caller you couldn't find their item to evict, when they were trying to retrieve something not evict something.
As for not mutating in a match guard, the mutation is an internal detail, not part of the public interface.
Yes, this argues for maybe using a RefCell for internal mutability to avoid the semantically-inaccurate exposure of that internal mutation through the &mut self on recently_evicted(). That's a valid point and a better solution. I should probably get more comfortable with RefCell; for some reason the concept rubs me the wrong way, though I don't have any problem with the comparable C++ construct (a mutable field).
Another option is to forgo the optimization of removing the already-reported eviction record from recently_evicted. This isn't just a performance optimization, though, it's to maximize the number of callers who are informed about why their attempted operation failed while keeping the space strictly bounded (it's not actually a Vec in the real code, nor is the HashMap a std::HashMap -- this code runs on a tiny microcontroller with no heap). There's quite a bit more to it than my very-simplified example showed -- but every way of doing it requires mutating the recently_evicted record.
As for the comments about not returning &mut, the other option is to remove and re-add the entry on every usage, which is far worse than searching the map twice. `get_mut()` is not evil. It exists for very good reasons.