Even just scanning through it I saw `Avoid matching Option and Result` and the `if let` stuff that I have NOT been using and it looks much more concise already.
Even just scanning through it I saw `Avoid matching Option and Result` and the `if let` stuff that I have NOT been using and it looks much more concise already.
When I first started using Rust I did make the mistake of matching Option and Result everywhere and when I learned better I did cut out quite a bit of verbosity and unnecessary nesting by going back and refactoring those in code I had written. But that doesn't mean you should never use match with them. I thought I should share this experience for anyone new to the language reading this.
pub fn encrypted(&self) -> Vec<u8> {
encrypt(self.payload.as_ref().unwrap_or(&vec![]))
}
Needlessly allocates a `Vec` if `self.payload` is `Some`. Really you should do: encrypt(&self.payload.as_ref().unwrap_or_else(|| &vec![]))
But that isn't going to work because the `else` Vec will be dropped at the end of the closure.In this situation (if the code was on a hot path where every bit of performance mattered) I would probably do something like:
match self.payload.as_ref() {
Some(payload) => encrypt(payload),
None => encrypt(&vec![])
}
There is a slight bit of duplicated code. I'd be curious if anyone could come up with a better way. if you construct a Vec with capacity 0 via Vec::new, vec![], Vec::with_capacity(0), or by calling shrink_to_fit on an empty Vec, it will not allocate memory.
So an empty vec![] is just a struct on the stack; very cheap to make, and easy for the compiler to optimize out if it can see that it's not used in some paths.When using unwrap_or(&vec![]), it lives in the enclosing stack. Without the reference, you could use unwrap_or_default().
self.payload.as_deref().unwrap_or_default()
...which I think is the best here.Empty vecs don’t require a heap allocation, so your original code is actually fine. In release mode it should compile to exactly the same instructions as your last example.
If that function was taking a reference to an object that was fairly expensive to create a default value for then my conundrum would still exist.
Vec is documented not to allocate if empty (unless created with a set capacity). So all the code does is store 3 u64 on the stack.
There is a growing bunch of people I've met that said the match stuff is overused.