loop != while true
意味的な違いはないと思われるloop {...}
とwhile true {...}
だが、変数制約チェックなどのパス解析では扱いが異なる。
// loopだとコンパイルできる
fn main() {
let mut a = 1;
let mut b = 2;
let mut x = &mut a;
println!("{}", x);
loop {
x = &mut b;
break;
}
let y = &mut a;
println!("{} {}", x, y);
}
// while trueだとコンパイルできない
fn main() {
let mut a = 1;
let mut b = 2;
let mut x = &mut a;
println!("{}", x);
while true {
x = &mut b;
break;
}
let y = &mut a; // ERROR: second mutable borrow occurs here
println!("{} {}", x, y);
}
x
によるa
の可変参照はループブロック内のx = &mut b;
によって解放されるが、while
ではブロックが実行されない可能性も考慮されるため、ループ後のy
に割り当てることができない。一方loop
では確実に解放されるとみなされるため、a
の可変参照はy
に割り当て可能と判定される。
上のようなwhile true
は単純にloop
に置き換えるだけで解決するが、他言語でみられる以下のようなパターンもwhile
のかわりにloop
(+break
)を使うべき事例があるかもしれない。
// 必ず1度は実行されるループ(do-whileなんてなかった)
let mut found = false;
while !found { // 見つかるまでループ
// 前処理
...
// 検索
found = ...
// 後処理
...
}
おまけ
// loopでも途中で抜ける素振りを見せるとコンパイルできない
fn main() {
let mut a = 1;
let mut b = 2;
let mut x = &mut a;
println!("{}", x);
loop {
if false { break; } // ここでbreakするかも(しない)
x = &mut b;
break;
}
let y = &mut a; // ERROR: second mutable borrow occurs here
println!("{} {}", x, y);
}
たとえ0%でも可能性は見逃さない。