@Aplet123 is of course right, that's the way to go and his answer should be marked correct.
But in case you wonder how to make this prettier, you could wrap it in a custom trait for Vec<Vec<T>>:
trait Get2D {
type Val;
fn get2d(&self, i: usize, j: usize) -> Option<&Self::Val>;
fn get2d_mut(&mut self, i: usize, j: usize) -> Option<&mut Self::Val>;
}
impl<T> Get2D for Vec<Vec<T>> {
type Val = T;
fn get2d(&self, i: usize, j: usize) -> Option<&T> {
self.get(i).and_then(|e| e.get(j))
}
fn get2d_mut(&mut self, i: usize, j: usize) -> Option<&mut T> {
self.get_mut(i).and_then(|e| e.get_mut(j))
}
}
fn main() {
let mut data: Vec<Vec<i32>> = vec![vec![1, 2, 3], vec![4, 5, 6]];
println!("{}", data.get2d(1, 1).unwrap());
*data.get2d_mut(0, 1).unwrap() = 42;
println!("{:?}", data);
}
5
[[1, 42, 3], [4, 5, 6]]