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/
環境構築
Rustの開発ツールはHomebrewで簡単にインストールできる。
rustc
やcargo
といったコマンドがインストールされる。
$ 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
参考: