I've realised I've simplified my code too much for this question, since here you could replace vec.get(i) with vec.len() <= i, but in my reall, messy code I actually iterate two vecs in parallel, because I want to peek the other vec's value if it exists. So assume vec.get(i) at the top is mandatory
I'm not 100% sure what you're trying to do, but in the future with non-lexical lifetimes, at least pattern-matching equivalents should work - i.e. this won't be a lifetime error:
let last = if let Some(x) = vec.get(i) {
x
} else {
vec.push(whatever);
vec.last().unwrap()
};
(But I don't think unwrap_or would work.)
The else part of that is awkward, but with another future feature, placement-new, I think it could be fully replaced with the expression vec <- whatever, which would append whatever to the vector and return a reference to it.
For now, I think you have to do it the ugly way. Your use case seems somewhat similar to that of VecMap, but that's a wrapper around Vec<Option<T>>, not Vec<T>. That is, indices may be omitted (but the map is densely populated enough that it makes sense to just represent it with a Vec rather than a proper hash map).
Two things that I don't like in the current solution:
I have to create another inner scope to peek the values.
I have to re-read elements from the vecs, since the initial get couldn't safely outlive the push.
HashMap has exactly the same problem, but solves it with the Entry API. I didn't see any such solution for Vec, so I was wondering if I missed some obvious alternative solution.
An entry API for Vec is not really straight forward. You cannot just insert a new element at an arbitrary index that is larger than the size.
You could always implement your own entry API that just returns an Option<Entry> or panics if the index is greater than the size, but I'm not sure if that's more elegant.