Im currently trying to optimize my code for readability and have run into issues when I'm indexing an array but also need to use negative number. Here's the example:
Explanation since its difficult to read:
This code is trying to go over every element in the vector and find the elements to the left and right of it. The right one is subsequently subracted from the left one and printed as output. If at any point an index is out of bounds it is replaced with 0
fn main() {
let vec = vec![1, 2, 3];
let mask = [-1, 1];
for i in 0..vec.len() {
let l_index = (i as i32 + mask[0]);
let left = if l_index >= 0 {vec.get(l_index as usize).unwrap_or(&0)}
else {&0};
let r_index = (i as i32 + mask[1]);
let right = if r_index >= 0 {vec.get(r_index as usize).unwrap_or(&0)}
else {&0};
println!("Sum: {}", *left as i32 - *right as i32);
}
}
Expected result:
Sum: -2
Sum: -2
Sum: 2
This code isn't an actual part of my code, just an example. This problem often occurs when I decide to use these 'masks' or when I'm doing linear Algebra in a 2d Grid, as you often have to subract or add possibly negative values.
The main point is, I have to do a total of 6 Type-conversions since I need support for negative numbers but also require the ability to index into an vector.
I also had to extract the index-equation into a seperate line: let l_index = (i as i32 + mask[0]);
. Otherwise I would've just written vec.get(i + mask[0])
.
In conclusion I find this code completely illegible for anyone unfamiliar with it. This case in particular isn't for a major codebase, however I want to follow the best practices even in my own codebases. I would like to find a way to improve the readability in cases where you need both the functionality of negative numbers as well as the ability to index an array safely. (I am very aware you can easily change how I set up the mask, however I have cases where such masks are much larger and would like to keep them simple.)
You can avoid most of the casts and the intermediate values by using wrapping_add
:
fn main() {
let vec = vec![1, 2, 3];
let mask = [-1i32 as usize, 1]; // or [usize::MAX, 1]
for i in 0..vec.len() {
let left = vec.get (i.wrapping_add (mask[0])).unwrap_or (&0);
let right = vec.get (i.wrapping_add (mask[1])).unwrap_or (&0);
println!("Sum: {}", *left as i32 - *right as i32);
}
}