電気ひつじ牧場

技術メモ

Rustにっき/1日目・HelloRust!

この記事について

Rustを勉強したかったので「プログラミングRust」に沿って勉強日記を書きます。 日記とか言っておきながら毎日続く保証は全くありません。これが最後の記事かもしれません。

Rustについて

概要

Firefoxの開発元であるMozillaとコミュニティにより2010年に発表された言語です。公式サイトを見ると、パフォーマンス、安全性、生産性を売りにしているのが分かります。オブジェクト指向や関数型など様々なパラダイムを取り込んだマルチパラダイム言語と言えます。

主な用途

OS、言語処理系、ネットワーク、組み込みなどのシステムプログラミングを主なターゲットとしているようです。これまでシステムプログラミングと言えばC, C++の独壇場でしたが、それらの言語が速度と引き換えに保証しない型安全性(言語のチェック機構が未定義動作を起こさないことを保証する性質)やそれから生み出される並行プログラミングの容易さなどがかつてのシステムプログラミング向けの言語を置き換えるのではないかと注目されています。

セットアップ

rustupというインストーラーがあります。rustupの公式ページに従って入れます。本題ではないので説明は省略。brewやビルド済みのパッケージを入れてもrustを利用できますが、rustupを使った方がrustのアップグレード等がrustup updateとするだけで簡単にできるため良いらしいです。

rustupをインストールすると、cargo, rustc, rustdocという3つのコマンドが利用できるようになります。

cargo

rustのビルドや、依存パッケージを管理するためのツールです。npmやgradleのようなものだと思います。

rustc

rustのコンパイラです。rustのコンパイルは通常cargoを使って行いますが、直接このコマンドを叩いてもコンパイルすることができます。

rustdoc

rustのドキュメンテーションツールです。ソースコード中に決められたフォーマットでコメントを書けば、ドキュメントを生成してくれます。これもcargoから間接的に利用します。

初めてのプロジェクト

プロジェクトの作成

cargoコマンドを利用します。

$ cargo new --bin hello

srcディレクトリにmain.rsが作成されて、helloworldがすでに記述されています。cargoは挨拶までも自動化してくれる素晴らしいツールですね。

fn main() {
    println!("Hello, world!"); 
} 

実行

実行してみます。例によってcargoを使います。

$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.48s
     Running `target/debug/hello`
Hello, World

やったーハローワールドできました。これでもう「Rustできます!」と面接でドヤることができます(できない)。

ディレクトリ構成

プロジェクトルートから第3階層までのディレクトリ構成はこんな感じです。結構色々作成されていますね。

.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        ├── examples
        ├── hello
        ├── hello-8a37362636b60b34
        ├── hello-8a37362636b60b34.d
        ├── hello-8a37362636b60b34.dSYM -> deps/hello-8a37362636b60b34.dSYM
        ├── hello.d
        ├── hello.dSYM -> deps/hello-defc3050e9d94550.dSYM
        ├── incremental
        └── native

実行ファイルはtarget/debug/helloなので、ビルド後はそれを直接実行することもできます。

$ ./target/debug/hello
Hello, World

ハロワも無事に行うことができました。

フィボナッチ数列

私は nasmアセンブリでフィボナッチ数列を書くほどフィボナッチ数列信者なので、Rustでも早速書いてみます。

fn fibonacci(n: u64) -> u64{
    if n == 0 || n == 1 {
        return n;
    }
    fibonacci(n-2) + fibonacci(n-1)
}

fnで関数の定義、u64として64ビットのunsignedな整数で引数と戻り値の型を定義しています。ブロック中の最後の文をセミコロンなして記述するとそれがそのブロックの戻り値となります。

テストコード

#[test]
fn test_fibonacci() {
    // 0 1 1 2 3 5
    assert_eq!(fibonacci(5), 5);

    assert_eq!(fibonacci(1), 1);
}

#[test]の後に関数を記述するとテストコードを書くことができます。テストを実行してみます。

$ cargo test
Compiling hello v0.1.0 (/Users/teru/works/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.57s
     Running target/debug/deps/hello-8a37362636b60b34
running 1 test
test test_fibonacci ... ok

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

テストコードはプロジェクト内のどのファイルに書いてもcargoが探してきてくれるらしいです。かしこい。

今日はこの辺りで終わり。次あたりは型の話について書きたい