19
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

FizzBuzzで学ぶenumとDisplay, Fromトレイト

無駄に長い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ライフを!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
19
Help us understand the problem. What are the problem?