Rust の slice の windows (OS ではない)
使い方
「Rust windows」でググっても Windows(OS) で Rust をやってみる系の話しか出てこないので、書いておこうとなりました。
std::slice::windows
は、「前の値も含めて for ループを回したい」というユースケースで使うことができます。競技プログラミングなどでは頻出なのではないでしょうか。
let v = vec![1, 2, 3];
for w in v.windows(2) {
let (prev, next) = (w[0], w[1]);
println!("{} {}", prev, next)
}
// 1 2
// 2 3
windows メソッドを用いると、ミュータブルな変数を外側のスコープに用意するという手間を省くことができます。とてもきれいに書くことができるようになると思います。
また、引数に 2 を与えていることから察しがつくと思いますが、引数に与えたサイズのウィンドウでのイテレータを得ることができます。
引数に 3 などを与えると、3つずつのイテレータを得られます。
let v = vec![1, 2, 3, 4];
for w in v.windows(3) {
let (prev, current, next) = (w[0], w[1], w[2]);
println!("{} {} {}", prev, current, next)
}
// 1 2 3
// 2 3 4
注意
注意というほど注意でもないのですが、std::slice::Iter
からは生えません。
iter()
を挟むと、以下のようにコンパイルエラーとなります。
let v = vec![1, 2, 3];
for w in v.iter().windows(2) {
let (prev, next) = (w[0], w[1]);
println!("{} {}", prev, next)
}
// 1 2
// 2 3
Compiling playground v0.0.1 (/playground)
error[E0599]: no method named `windows` found for struct `std::slice::Iter<'_, {integer}>` in the current scope
--> src/main.rs:5:23
|
5 | for w in v.iter().windows(2) {
| ^^^^^^^ method not found in `std::slice::Iter<'_, {integer}>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
おそらく、サイズが決まっていて、s[lo..hi]
のようにスライスでアクセスできるような並びに対してしか使えないことになっている(?)のだと思います。
itertools の windows
また、 itertools
にはこれをタプルにした tuple_windowsがあります。
タプルにすると何がうれしいかというと、for文の1行目に書いているようなlet文の変数束縛フェーズがスキップできます。また、明示的に引数にサイズを与える必要もなくなり、for文の受け取り側のタプルの型から型推論してくれるようです。かしこい。
use itertools::Itertools;
fn main() {
let v = vec![1, 2, 3];
for (prev, next) in v.iter().tuple_windows() {
println!("{} {}", prev, next)
}
// 1 2
// 2 3
}
こちらではiter()
を挟まないと、「the method `tuple_windows` exists but the following trait bounds were not satisfied:」というエラーが出ます。 Rust 難しい…