19
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RustAdvent Calendar 2017

Day 24

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

Last updated at Posted at 2017-12-23

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

19
18
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?