Rhythm & Biology

Engineering, Science, et al.

2018年 Rustチャレンジ

2018年に新しく学ぶ言語としてRustにチャレンジしてみる。

Rustのドキュメント(邦訳)を見ながら進める。
http://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/

ドキュメントの本家はこっち。
https://doc.rust-lang.org/book/

環境構築

macOS Sierra上に環境構築する。

Rustの開発ツールはHomebrewで簡単にインストールできる。
rustccargoといったコマンドがインストールされる。

$ brew install rust

新規プロジェクト作成

Cargoを利用してプロジェクトを作成する。
バイナリを作成するため--binオプションをつける。

$ cargo new rustlang-intro --bin
$ cd rustlang-intro/
$ cargo build
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/rustlang-intro`
Hello, world!

リリースビルドをするには--releaseオプションをつける。
すると、target/releaseの下に成果物が作成される。

$ cargo build --release

標準入力

標準入力で受けた文字列を標準エラー出力に表示する。

use std::io;

fn print_stdin() {
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line);
    eprintln!("{}", line.trim());
}

乱数生成

randクレートを利用して乱数を生成・表示する。

まず、Cargo.tomlに依存関係を記述する。

[dependencies]
rand = "0.4.1"

10回乱数を生成して表示する。

extern crate rand;

fn print_random_numbers() {
    for _ in 0..10 {
        let n = rand::random::<i32>();
        println!("{}", n)
    }
}

こう書くこともできる。

extern crate rand;

use rand::Rng;

fn print_random_numbers() {
    let mut rng = rand::thread_rng();
    for _ in 0..10 {
        let n = rng.gen::<i32>();
        println!("{}", n)
    }
}

構造体

構造体を作る。メソッド実装にはimplブロックを利用する。
newメソッドで構造体初期化を行なっているが、メソッド名は慣習でしかなく、名前はなんでも良い。
また、このようにselfを引数に持たないメソッドは関連関数(associated function)と呼ばれるが、他の言語で言う静的メソッド(static method)に該当するものと思っておけば良い。

struct Person {
    name: String,
}

impl Person {
    fn new(name: &str) -> Person {
        Person {
            name: name.to_string(),
        }
    }

    fn get_name(&self) -> &String {
        &self.name
    }
}

fn main() {
    let p = Person::new("person's name");
    println!("{}", p.get_name());
}

ちなみに、以下のようなコードを書いてしまうとエラーになる。
借り物(self)から勝手に所有権をmoveできないということ。
上のコードのように参照で返すようにしなければコンパイルが通らない。

    fn get_name(&self) -> String {
        self.name
    }
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:33:9
   |
33 |         self.name
   |         ^^^^ cannot move out of borrowed content

トレイト

trait Hello {
    fn say(&self);
}

impl Hello for Person {
    fn say(&self) {
        println!("Hello {}", self.name);
    }
}

fn main() {
    let h = Person::new("trait");
    h.say();
}

マクロ

引数なし版と引数あり版の簡単なものを作ってみる。

macro_rules! say_hello {
    () => {
        println!("Hello");
    };
    ($x:expr) => {
        println!("Hello {}", $x);
    };
}

fn main() {
    say_hello!();
    say_hello!("name");
}

テスト

テストを書いてみる。
慣習的にテストコードを入れる専用のモジュールを作っておくらしい。cargo testのときだけコンパイルされる条件付きコンパイルのフラグをつけておく。

fn add(x: i64, y: i64) -> i64 {
    return x + y;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add() {
        assert_eq!(10, add(4, 6));
    }
}
$ cargo test
...(中略)...
running 1 test
test tests::test_add ... ok

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

まとめ

環境構築から基本的な記述まで試すことができた。
借用の概念がまだ自分の中で綺麗に整理できていないのでもう少し資料を漁りながら試してみることにする。
今度はマルチスレッドでHTTPサーバでも実装してみる。