ドキュメント
公式が一番参考になるのでぐぐる必要はない
(crate.ioよりも洗練されてて事実上の標準ライブラリがわかるようになっていてよい)
命名規約
Clippy
Cookbook
必須ツール
代表的なプロダクト
基本
文字列
7文字制限だと
Copy format!("{:0>7.7}", string);
関数の引数の入出力
入力は&str
(がんばるなら>(s: S)がいい)、出力はString
がよい気がする
型変換
リファクタリング
ファイル分割
OptionとResultの使い方
イテレータ
非同期プログラミング
rust-jp slackのtatsuya6502さんのコメントより
実行キューが常に複数プロセッサ(複数のOSスレッド)からアクセスされるため、タスク切り替えのオーバーヘッドが高い。(非同期タスクではタスク切り替えの頻度が非常に高く、性能への影響が大きい)
実装がシンプル(ランタイムがバグりにくい)
Many processors, each with their own run queue
個々のプロセッサがそれ専用の実行キューを持つタイプ
タスクのスケジューリングにばらつきがでる(不公平)
実行キューが単一のプロセッサ(OSスレッド)からしかアクセスされないため、タスク切り替えのオーバーヘッドが低い
性能は2番に近く、2番の欠点である不公平なスケジューリングの解決を図ったもの
個々のプロセッサがそれ専用の実行キューを持つが、プロセッサが暇になると他のプロセッサの実行キューからタスクを奪うタイプ
ほとんどの場合、実行キューが単一のプロセッサ(OSスレッド)からアクセスされるため、タスク切り替えのオーバーヘッドが低い
テストコード
単体テストコードはソースコードの中に書く。modでくくる
Copy #[cfg(test)]
mod tests {
use super::add_two;
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
}
結合テストはtests/
ディレクトリに格納する
テストデータの置き場
rlsはtests/fixtures/に置いてる模様
Cargo
Cargoで使える環境変数
OUT_DIR: ./target/debug/build/xxx-hashyyy/out
テスト
Tips
FixtureTest
FixtureTestは2019/07/12現在サポートされていない。
デバッグ
lldb
型を表示する
type lookup xxx
仕様
借用と参照と関数の引数の関係
後置のif
ない模様
CI
CIでやること
よく使う構文
Vecの要素を条件ごとに削除したりしたい
Copy let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
現在時刻取得
Utc::now().naive_utc()
static変数
Copy let x: &'static str = "Hello, world.";
static Foo: i32 = 5;
let x: &'static i32 = &FOO;
よく使うcrate
clap
引数処理
特定の値だけを許容してenumに突っ込みたい
possible_valuesを使ってfrom_strで変換するのがよさげ
並列/並行処理
スレッド
Tips
&OptionからOptionに変換したい
aaa.as_ref() でOption<&T>に変換して、 aaa.as_ref().cloned() でOptionにする
OsStringからfailtureに変換する
the trait std::error::Error
is not implemented for std::ffi::OsString
Copy pathbuf.
.into_os_string()
.into_string()
.map_err(|x| format_err!("Home env not found {:?}", x))?)
boolをResult型に変換する
boolinatorを使うのがよさそう
文字列から改行を削除する
Copy fn trim_newline(s: &mut String) {
while s.ends_with('\n') || s.ends_with('\r') {
s.pop();
}
}
Copy let len = input.trim_end_matches(&['\r', '\n'][..]).len();
input.truncate(len);
関数の引数でたくさんの型を許容したい
&Tとmut &Tを受け付けたい: Borrowを使う
Pathっぽいものを受け付けたい:AsRefを使う
&strとStringを受け入れたい: Into or AsRef
非同期で関数をループ実行
Copy fn run_async<P: AsRef<Path>>(
input_files: &Vec<P>,
) -> Result<Vec<PathBuf>, Error> {
let v = Arc::new(Mutex::new(vec![]));
thread::scope(|s| -> Result<(), Error> {
for input_file_ in input_files {
let input_file = input_file_.as_ref().clone();
let v = Arc::clone(&v);
s.spawn(move |_| -> Result<(), Error> {
let output_file = format!(
"out_{}",
input_file
.file_stem()
.ok_or(format_err!("Could not convert to filename"))?
.to_str()
.ok_or(format_err!("Could not convert to string"))?
);
let mut v1 = v.lock().unwrap();
match run_app(&input_file, &output_file) {
Ok(p) => v1.push(p),
Err(e) => warn!(
"Error Occured!: {}. Skip: {}",
e.to_string(),
&output_file
),
}
Ok(())
});
std::thread::sleep(std::time::Duration::from_secs(0));
}
Ok(())
})
.map_err(|_| format_err!("Thread execution error"))?
.map_err(|e| format_err!("Thread execution error: {}", e))?;
let ret = v
.lock()
.map_err(|e| format_err!("lock error: {}", e))?
.to_vec();
Ok(ret)
}
std::threadで? operatorを使いたい
fast returnしたいときのやり方。closureに戻り値を書く
ジェネリクスでの型を指定する
turbofish ::<>を使う
Copy let _a = AAA::<i64>(0);
最適化したい
rustcにオプションをつける -C opt-level=3 -C debug_assertions=no
lines()でreferenceが使えない
by_ref()を使う
unit testでプロジェクトルートを取得する
Copy let mut project_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
build.rsでprintlnする
cargo build --verbose -vv
で表示できる。表示されないときはファイルを一部更新してもう一度実行してみる。
リポジトリが変更されたら強制的にbuild.rsを呼び出すようにする方法
エラーメッセージでNo such file or directoryがどのファイルかわからない
mainで早期リターン
1.26からはmainで?が使えるのでそれを使ったほうがいい。
Copy use std::fs;
fn main() -> Result<(), std::io::Error> {
let _ = fs::File::create("bar.txt");
let _ = if let Ok(val) = fs::File::open("bar.txt") { val } else { println!("aaaa"); return Ok(())};
println!("bbbb");
Ok(())
}
ワイルドカード(glob)でファイルを消す
Copy let _ = glob(glob_pattern)
.expect("Failed to read glob pattern")
.for_each(|path| fs::remove_file(path.as_ref().unwrap()).unwrap());
文字列で0パディングする
ファイルの更新日時が最新のものを取得する
Copy let new_generated = glob(&*glob_pattern)
.expect("Failed to read glob pattern")
.max_by_key(|path| {
fs::metadata(path.as_ref().unwrap())
.unwrap()
.modified()
.unwrap()
})
.unwrap()?;
StringをErrorに変換したい(the trait bound &str: std::error::Error
is not satisfied)
format_err!()マクロを使う
OptionalをResultに変換したい
ok_orを使う
info!,debug!をユニットテストでも出力させたい
env_loggerを使って、
Copy env::set_var("RUST_LOG", "info");
let _ = env_logger::builder().is_test(true).try_init();
をsetupかなにかで毎回実行させる
coverageを表示したい
Copy cat target/coverage/kcov-merged/coverage.json | jq -r '[.percent_covered, .covered_lines, .total_lines] | @sh' | tr -d \' | awk '{ printf "coverage: %s%% (%d / %d)\n", $1, $2, $3 }'
cargo makeなら
Copy [tasks.coverage-show]
script = [
'''
#!/usr/bin/env bash
cat target/coverage/kcov-merged/coverage.json | jq -r '[.percent_covered, .covered_lines, .total_lines] | @sh' | tr -d \' | awk '{ printf "coverage: %s%% (%d / %d)\n", $1, $2, $3 }'
'''
]
serdeで項目名を変更したい
Copy #[serde(rename = "pos[0]")]
pos_0: Option<f64>,
をフィールドにつけてリネームする
serdeでシリアライズとデシリアライズの名称を変えたい
Copy struct Joeybloggs {
#[serde(rename(deserialize = "old", serialize = "new"))]
field: i32,
}
テストデータの置き場をプロジェクトルートからの相対パスで取得する方法
Copy let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/test");
TroubleShooting
テストを書いたのに実行されない
{module-name}.rs or mod.rsにpub mod xxxの記述がないため実行ファイルからテストが呼び出せないことが原因。追加すること。
参考サイト