#無駄に長いFizzBuzz
Rustは型の扱いなどは厳格で、いい加減な書き方をさせてもらえない言語ですが、
一方で、プログラムを短くスマートに分かりやすく書く機能も充実しています。
今回は、FizzBuzzをenumで定義してDisplayトレイトやFromトレイトを実装することで、
println!
する部分を極力シンプルにしてみました。
FizzBuzzを書くにしては、えらく冗長で遠回りな作りですが、
みなさんよくご存知のFizzBuzzでこれらの機能の使い方を見ていけたらいいな、と思います。
use std::fmt;
enum FizzBuzz {
Fizz,
Buzz,
FizzBuzz,
Number(u32),
}
impl fmt::Display for FizzBuzz {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FizzBuzz::Fizz => write!(f, "Fizz"),
FizzBuzz::Buzz => write!(f, "Buzz"),
FizzBuzz::FizzBuzz => write!(f, "FizzBuzz"),
FizzBuzz::Number(n) => write!(f, "{}", n),
}
}
}
impl From<u32> for FizzBuzz {
fn from(n: u32) -> FizzBuzz {
if n % 15 == 0 {
FizzBuzz::FizzBuzz
} else if n % 3 == 0 {
FizzBuzz::Fizz
} else if n % 5 == 0 {
FizzBuzz::Buzz
} else {
FizzBuzz::Number(n)
}
}
}
fn main() {
(1..101).map(|n| n.into()).for_each(|e: FizzBuzz| println!("{}", e));
}
#Rustのenum
Rustでは、enumはCなどでおなじみの単なる列挙型としてだけではなく、変数を持たせられます。
enum FizzBuzz {
Fizz,
Buzz,
FizzBuzz,
Number(u32),
}
今回、3で割り切れて5で割り切れないことを表すFizz
, 5で割り切れて3で割り切れないことを表すBuzz
, 3で割り切れてかつ5で割り切れることを表すFizzBuzz
、3でも5でも割り切れないNumber(u32)
の値を持てるように作ってみました。
#fmt::Display
fmt::Display
トレイトは、println!("{}", x)
などで表示したときのフォーマットを定義するトレイトです。
FizzBuzzのルールに従ったフォーマットを定義しました。
#From
From<T>
を定義することで、FizzBuzz::from(t)
ができるようになります。また、T::into::<FizzBuzz>(t)
も使えるようになります。
ここでは、整数からFizzBuzzへの変換について定義しています。
#イテレータ部分
コメントで説明します。
// 1から100までの整数のイテレータです。型推定がいい感じに働いて、u32になっているはずです。
(1..101)
// u32をFizzBuzz型に変換しています。後段で型を指定しているため、これだけで型推定が働く仕組みになっています。
.map(|n| n.into())
// inspect自体は値を加工せず、そのまま後段に渡します。デバッグなどの用途に適しています。
.inspect(|e: &FizzBuzz| println!("{}", e))
// イテレータの最後の値を返すためのものですが、イテレータを最後まで進めるためにダミーで入れています。
.last();
#まとめ
Rustの機能をうまく使って型を定義し、トレイトを実装すると、型を使う段階で楽ができます。
みなさま、よきRustライフを!