⬜
Rustで配列を扱う際の型変換地獄を避ける
はじめに
備忘録です。Rustc1.70.0で検証したやつなので、他のバージョンで動作することは保証しません。
解決したい問題
普通に書くと、負数を扱うので型変換が発生してちょっと面倒くさい。
static DI: &[isize] = &[0, -1, 0, 1];
static DJ: &[isize] = &[-1, 0, 1, 0];
fn main() {
// ...前略
for i in 0..h {
for j in 0..w {
for r in 0..4 {
let ni = i as isize + DI[r];
let nj = j as isize + DI[r];
if ni >= 0 && ni < h as isize && nj >= 0 && nj < w as isize {
v[ni as usize][nj as usize] = 1;
}
}
}
}
}
解決法
wrapping_add
を使ってあげると良い。wappring_add
は桁溢れを無視して加算を行ってくれる。
static DI: &[usize] = &[0, !0, 0, 1];
static DJ: &[usize] = &[!0, 0, 1, 0];
fn main() {
// ...前略
for i in 0..h {
for j in 0..w {
for r in 0..4 {
let ni = i.wrapping_add(DI[r]);
let nj = j.wrapping_add(DJ[r]);
if ni < h && nj < w {
v[ni as usize][nj as usize] = 1;
}
}
}
}
}
例えば、ABC302B - Find snukeのような問題では、周辺1マスのみならず、2マス、3マス先にアクセスしたい(= v[i - 2][j - 2]
のようなちょっと遠いところを見たい)場合、warpping_sub
を使ってあげるとうまくいく。
static DI: &[usize] = &[0, !0, 0, 1];
fn main() {
let i :usize = 5;
// 4 3 2 1 0
for k in 0..5 {
let ni = i.wrapping_add(DI[1].wrapping_sub(k));
print!("{} ", ni);
}
println!();
let i :usize = 2;
// 1 0 18446744073709551615 18446744073709551614 18446744073709551613
for k in 0..5 {
let ni = i.wrapping_add(DI[1].wrapping_sub(k));
print!("{} ", ni);
}
println!();
}
記述量が減ってかなり楽になるのでおすすめです。
Discussion