エンジニアになりたい

エンジニアです

RustでFizzBuzz

プログラミング言語Rustと、そのパッケージマネージャであるCargoを使ってFizzBuzzを書いていく。

要件は以下の通り。

1. 3の倍数の数字の時はfizzを出力
2. 5の倍数の数字の時はbuzzを出力
3. 3と5の倍数の数字の時はfizzbuzzを出力
4. それ以外の数字の時はそのまま数字を出力

雛形を作って実行

以下のように雛形を作る。

$ cargo new RustFizzBuzz --bin

Cargoを使って以下のように実行出来る。

$ cd RustFizzBuzz
$ cargo run
Hello, world!

これはsrcディレクトリ下のmain.rsが実行されることで表示されてる。

テストを書く

ルート下にtestsディレクトリを作って以下の内容のtest_rust_fizzbuzz.rsを設置する。Cargoはtestsという名前のディレクトリを見て、そこにあるテストファイルを実行してくれる。

extern crate RustFizzBuzz;
use RustFizzBuzz::rust_fizzbuzz;

#[test]
fn _1is_1() {
    assert_eq!("1", rust_fizzbuzz::fizzbuzz(1));
}

これはRustFizzBuzzクレイトをリンクして、その中のrust_fizzbuzzモジュールを使用するという意味である。最初に雛形を作る時点でRustFizzBuzzクレイトは作られている。

モジュールrust_fizzbuzzを定義するために、src下に以下の内容のlib.rsファイルを作成する。

pub mod rust_fizzbuzz;

このように宣言するとCargoはsrcディレクトリ下のrust_fizzbuzz.rsファイルを見つけてモジュール化してくれる。

それではsrc下に以下のような内容のrust_fizzbuzz.rsファイルを作成する。

pub fn fizzbuzz(n: i32) -> String{
    return n.to_string();
}

この時点でディレクトリ構造は以下のようになっているはず。

├── Cargo.lock
├── Cargo.toml
├── src
│   ├── lib.rs
│   ├── main.rs
│   └── rust_fizzbuzz.rs
└── tests
    └── test_rust_fizzbuzz.rs

ここまで書けばテストが実行出来るはずなので、以下のようにして実行する。

$ cargo test
tests is correct? [n,y,a,e]: n
   Compiling RustFizzBuzz v0.1.0 (file:///home/pro/RustProjects/RustFizzBuzz)
     Running target/debug/test_rust_fizzbuzz-50ecfb7694c5c790

running 1 test
test can_test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

実装

以下のように実装を行った。

pub fn fizzbuzz(n: i32) -> String{
    match n {
        n if n % 5 == 0 && n % 3 == 0 => "fizzbuzz".to_string(),
        n if n % 5 == 0 => "buzz".to_string(),
        n if n % 3 == 0 => "fizz".to_string(),
        _ => n.to_string()
    }
}

テストコードは以下のようになった。

extern crate RustFizzBuzz;
use RustFizzBuzz::rust_fizzbuzz;
#[test]
fn can_test() {
    assert_eq!(1, 1);
}
#[test]
fn _1is_1() {
    assert_eq!("1", rust_fizzbuzz::fizzbuzz(1));
}
#[test]
fn _3is_fizz() {
    assert_eq!("fizz", rust_fizzbuzz::fizzbuzz(3));
}
#[test]
fn _5is_buzz() {
    assert_eq!("buzz", rust_fizzbuzz::fizzbuzz(5));
}
#[test]
fn _15is_fizzbuzz() {
    assert_eq!("fizzbuzz", rust_fizzbuzz::fizzbuzz(15));
}

このままだと実装が微妙なのでリファクタリングを行って以下のようになった。

pub fn fizzbuzz(n: i32) -> String {
    match (n % 3, n % 5) {
        (0, 0) => "fizzbuzz".to_string(),
        (_, 0) => "buzz".to_string(),
        (0, _) => "fizz".to_string(),
        _ => n.to_string()
    }
}

テストも全部通ったので大丈夫そう。

まとめ

プロジェクトを作るところから、テストを書いて、モジュールとして実装、リファクタリングまでを行った。Cargo1つで何でも出来るという感じで、とても楽だった。

今回書いたものは全てGitHub上においてある。もうちょっと改良している。

github.com