はじめに
RustでPythonライクなrangeを使う方法を紹介します。
以下のように使うことができます。
// for i in range(5):
// print(i)
for i in range!(5) {
println!("{}", i);
}
// for i in range(1, 5):
// print(i)
for i in range!(1, 5) {
println!("{}", i);
}
// for i in range(1, 5, 2):
// print(i)
for i in range!(1, 5, 2) {
println!("{}", i);
}
// for i in range(5, 1, -1):
// print(i)
for i in range!(5, 1, -1) {
println!("{}", i);
}
やり方
以下のマクロでPythonライクなrangeを実装できます。
macro_rules! range {
($stop:expr) => {
0..$stop
};
($start:expr, $stop:expr) => {
$start..$stop
};
($start:expr, $stop:expr, -$step:expr) => {
($stop + 1..$start + 1).rev().step_by($step)
};
($start:expr, $stop:expr, $step:expr) => {
($start..$stop).step_by($step)
};
}
基本的には、Pythonのrange関数と同じイテレータを返します。
できないこと
負のステップを指定するときに、step_by()
はusize
しか受け取れないため、rev()
でイテレータを逆順にする必要があります。
そこでパターンマッチで-
の有無を判定して、rev()
するかを決めています。
なので変数に負の数が入っていてステップとして与えると、パターンマッチで負の数と判定することができないため、コンパイルエラーとなります。
// コンパイルエラー
let x = -1;
for i in range!(5, 1, x) {
println!("{}", i);
}
ここらへんをうまく実装できる方法があれば、教えていただきたいです。
最後に
Rustのマクロは自由度が高いので、とても楽しいです。