2014/09/04

プログラミング言語RustでFizz-Buzzしてみる

最近やや盛り上がりつつあるRustを使ってみることにしました。

試しに、RustとパッケージマネージャCargoを導入してから、Fizz-Buzzを書いてみました。

RustとCargoの導入

Rustの導入

Rustは古いバージョンだと上手く動かなかったりするのでNightlyバージョンを導入しましょう。

Homebrewだとちょっと古いバージョンになるので、今回は公式ページからMac binaries (.tar.gz) の64-bit版をダウンロードしました。 インストールにはこれを解凍してinstall.shを実行するだけです。

$ tar zxvf ~/Downloads/rust-nightly-x86_64-apple-darwin.tar.gz
$ cd rust-nightly-x86_64-apple-darwin
$ ./install.sh

これで、/usr/localあたりにrustcがインストールされます。あとは、/usr/local/binにパスを通せばよいです。

$ rustc --version
rustc 0.12.0-pre-nightly (2e3858179 2014-09-03 00:51:00 +0000)

Cargo

パッケージマネージャのCargoGitHubページのリンクからx86_64-apple-darwinをダウンロードして、その中のファイルcargo/usr/local/binに置きました。

$ cargo version 
cargo 0.0.1-pre-nightly (3139954 2014-09-03 05:22:14 +0000)

新規プロジェクトの作成

CargoでRustの新規プロジェクトを作成するにはcargo newします。

$ cargo new --bin --git fizzbuzz

プロジェクト用ディレクトリfizzbuzzが生成されます。

$ cd fizzbuzz
$ ls -a
./      ../     .git/       .gitignore  Cargo.toml  src/    
$ ls src 
main.rs

--binを付けたのでバイナリ向けのテンプレートが生成されており、--gitを付けたので.git.gitignoreが生成されています。 ファイルはトラックされていないので、すぐにcommitしてしまってもよいでしょう。

cargo用の設定ファイルCargo.tomlはこんな感じ。今回は何も手を入れずに利用しています。

$ cat Cargo.toml 
[package]

name = "fizzbuzz"
version = "0.0.1"
authors = ["Safx <safxdev@example.com>"]

ちなみにcargoを引数なしで実行するとこんな感じになります。

$ cargo
Rust's package manager

Usage:
cargo <command> [<args>...]
cargo [options]

Options:
-h, --help       Display this message
-V, --version    Print version info and exit
--list           List installed commands
-v, --verbose    Use verbose output

Some common cargo commands are:
build       Compile the current project
clean       Remove the target directory
doc         Build this project's and its dependencies' documentation
new         Create a new cargo project
run         Build and execute src/main.rs
test        Run the tests
bench       Run the benchmarks
update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.

試しにコンパイル

cargo newで生成されたソースファイルはこんな感じです。

$ cat src/main.rs
fn main() {
    println!("Hello, world!")
}

とりあえずコンパイルしてみます。これにはcargo buildするだけです。

$ cargo build
Compiling fizzbuzz v0.0.1 (file:///Users/safx/src/fizzbuzz)

これで、targetというディレクトリが生成されて、その中にfizzbuzzというバイナリが生成されます。

$ ./target/fizzbuzz 
Hello, world!

テストを書く

テストファーストでFizz-Buzzを書いていきますので、テストとfizzbuzzの空実装を書きます。

fn fizzbuzz(n: int) -> String {
   "".to_string()
}

#[test]
fn test_fizz() {
    assert_eq!(fizzbuzz(3), "fizz".to_string())
    assert_eq!(fizzbuzz(6), "fizz".to_string())
    assert_eq!(fizzbuzz(9), "fizz".to_string())
}

Rustでは#[test]がある関数はテストケースとしてテスト時に実行されます。テストを実行してみましょう。

$ cargo test
   Compiling fizzbuzz v0.0.1 (file:///Users/safx/src/fizzbuzz)
/Users/safx/src/fizzbuzz/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
/Users/safx/src/fizzbuzz/src/main.rs:1 fn main() {
/Users/safx/src/fizzbuzz/src/main.rs:2     println!("Hello, world!")
/Users/safx/src/fizzbuzz/src/main.rs:3 }
/Users/safx/src/fizzbuzz/src/main.rs:5:14: 5:15 warning: unused variable: `n`, #[warn(unused_variable)] on by default
/Users/safx/src/fizzbuzz/src/main.rs:5 fn fizzbuzz(n: int) -> String {
                                                    ^
     Running target/fizzbuzz-c2448ebfc140711f

running 1 test
test test_fizz ... FAILED

failures:

---- test_fizz stdout ----
    task 'test_fizz' failed at 'assertion failed: `(left == right) && (right == left)` (left: ``, right: `fizz`)', /Users/safx/src/fizzbuzz/src/main.rs:11

failures:
    test_fizz

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

このテストを通すようにします。

fn fizzbuzz(n: int) -> String {
    if n % 3 == 0 {
        "fizz".to_string()
    } else {
       "".to_string()
    }
}

これでテストが通るようになりました。

$ cargo test
   Compiling fizzbuzz v0.0.1 (file:///Users/safx/src/fizzbuzz)
/Users/safx/src/fizzbuzz/src/main.rs:1:1: 3:2 warning: code is never used: `main`, #[warn(dead_code)] on by default
/Users/safx/src/fizzbuzz/src/main.rs:1 fn main() {
/Users/safx/src/fizzbuzz/src/main.rs:2     println!("Hello, world!")
/Users/safx/src/fizzbuzz/src/main.rs:3 }
     Running target/fizzbuzz-c2448ebfc140711f

running 1 test
test test_fizz ... ok

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

実装

そんなこんなで完成したFizz-Buzzがこちら。

fn main() {
    for i in range(1, 31) {
        println!("{}", fizzbuzz(i))
    }
}

fn fizzbuzz(n: int) -> String {
    if n % 15 == 0 {
        "fizzbuzz".to_string()
    } else if n % 3 == 0 {
        "fizz".to_string()
    } else if n % 5 == 0 {
        "buzz".to_string()
    } else {
        n.to_string()
    }
}

#[test]
fn test_num() {
    assert_eq!(fizzbuzz(1), "1".to_string())
    assert_eq!(fizzbuzz(2), "2".to_string())

    assert_eq!(fizzbuzz(4), "4".to_string())

    assert_eq!(fizzbuzz(29), "29".to_string())
}

#[test]
fn test_fizz() {
    assert_eq!(fizzbuzz(3), "fizz".to_string())
    assert_eq!(fizzbuzz(6), "fizz".to_string())
    assert_eq!(fizzbuzz(9), "fizz".to_string())
}

#[test]
fn test_buzz() {
    assert_eq!(fizzbuzz(5),  "buzz".to_string())
    assert_eq!(fizzbuzz(10), "buzz".to_string())
    assert_eq!(fizzbuzz(20), "buzz".to_string())
}

#[test]
fn test_fizzbuzz() {
    assert_eq!(fizzbuzz(15), "fizzbuzz".to_string())
    assert_eq!(fizzbuzz(30), "fizzbuzz".to_string())
}

ちなみに、cargo runで実行できます。コンパイルはそれなりに早いので割と気軽に実行できます。Goみたいですね。

$ cargo run
   Compiling fizzbuzz v0.0.1 (file:///Users/safx/src/fizzbuzz)
     Running `target/fizzbuzz`
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz

関連リンク

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。