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サーバでも実装してみる。

ファイルの先頭を指定行数ぶん読み飛ばす

ファイルの先頭から指定行数ぶん取り除きたいことがよくある。
例えば固定行数のヘッダがついており、それを除去したい場合。

tailコマンドを使えば簡単にできるが、他にどんな方法があるか色々試してみた。

8行のファイルを用意し、最初の3行を読み飛ばす。

$ cat sample.txt
1
2
3
4
5
6
7
8

tailを使う方法

「4行目から表示」という意味で+4とする(+3と間違えないように)。

$ tail -n +4 sample.txt
4
5
6
7
8

sedを使う方法

「1〜3行目を削除」とする。

$ sed 1,3d sample.txt
4
5
6
7
8

awkを使う方法

「行番号が3より大きければ表示」とする。

$ awk 'NR>3{print}' sample.txt
4
5
6
7
8

もっと簡単に書ける(printを省略)。

$ awk 'NR>3' sample.txt
4
5
6
7
8

perlを使う方法

awkと同じ考え方。

$ perl -ne '$.>3 && print' sample.txt
4
5
6
7
8

commを使う方法

headで先頭3行を取り出して元ファイルと比べ、共通部分を取り除く。
わざわざこんな書き方をするのは狂気でしかない。

$ head -n 3 sample.txt | comm -2 -3 sample.txt -
4
5
6
7
8

結論

tailで十分。
ただ、sed,awk,perlを使えば途中の数行読み飛ばすとかできるので汎用性は高い。

Python3.xでLocustを使う

現状、LocustはPython3.xには対応しておらず、2.xで利用しなければならない。
ただ、Python3.x対応版も準備されていて、それを利用することが可能。

普通にpipでLocustをインストールすると、locustio-0.7.5が入る。

$ pip install locustio
...(中略)...
Successfully installed Werkzeug-0.12.2 certifi-2017.7.27.1 chardet-3.0.4 click-6.7 flask-0.12.2 gevent-1.1.1 greenlet-0.4.12 idna-2.5 itsdangerous-0.24 locustio-0.7.5 msgpack-python-0.4.8 requests-2.18.3 urllib3-1.22

この状態で実行するとエラーが出る。

$ locust -f locustfile.py
...(中略)...
ModuleNotFoundError: No module named 'core'

Python3.xで利用するにはlocustio-0.8a2を明示的にインストールする。

$ pip install locustio==0.8a2

$ python -f locustfile.py

参考:

github.com