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上においてある。もうちょっと改良している。