公式が一番参考になるのでぐぐる必要はない
命名規約
https://sinkuu.github.io/api-guidelines/naming.html#%E5%A4%A7%E6%96%87%E5%AD%97%E5%B0%8F%E6%96%87%E5%AD%97%E3%81%AE%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91%E3%81%8Crfc430%E3%81%AB%E5%BE%93%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B-c-case
Clippy
https://rust-lang.github.io/rust-clippy/master/index.html
Cookbook
https://www.rust-lang.org/tools
https://qiita.com/YusukeHosonuma/items/13142ab1518ccab425f4
7文字制限だと
format!("{:0>7.7}", string);
入力は&str
(がんばるなら<S: Into
https://qiita.com/legokichi/items/0f1c592d46a9aaf9a0ea
https://doc.rust-jp.rs/book/second-edition/ch12-03-improving-error-handling-and-modularity.html
https://keens.github.io/blog/2018/12/08/rustnomoju_runotsukaikata_2018_editionhan/
https://qiita.com/tatsuya6502/items/cd41599291e2e5f38a4a
https://qiita.com/lo48576/items/34887794c146042aebf1
https://tech-blog.optim.co.jp/entry/2019/11/08/163000#Rust%E3%81%AE%E9%9D%9E%E5%90%8C%E6%9C%9F%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E7%89%B9%E5%BE%B4
rust-jp slackのtatsuya6502さんのコメントより
スケジューラ(または実行モデル)の分類について、上のOPTiMさんの記事ではM:Nモデルを「スレッドプール」と「ワークスティーリング」の2つに分けています。しかし実際にはスレッドプールと呼んでいるものがさらに2つに分かれて、しかも性能特性が逆なので少し注意が必要です。 https://tokio.rs/blog/2019-10-scheduler/ の記事の解説に合わせて3つに分類すると以下のようになります。(記事の図を見ると違いがわかりやすいです)
- One queue, many processors
- 単一の実行キューを複数プロセッサで共有するタイプ
- 全てのタスクが公平にスケジューリングされる
- 実行キューが常に複数プロセッサ(複数のOSスレッド)からアクセスされるため、タスク切り替えのオーバーヘッドが高い。(非同期タスクではタスク切り替えの頻度が非常に高く、性能への影響が大きい)
- 実装がシンプル(ランタイムがバグりにくい)
- Many processors, each with their own run queue
- 個々のプロセッサがそれ専用の実行キューを持つタイプ
- タスクのスケジューリングにばらつきがでる(不公平)
- 実行キューが単一のプロセッサ(OSスレッド)からしかアクセスされないため、タスク切り替えのオーバーヘッドが低い
- 実装がシンプル(ランタイムがバグりにくい)
- Work-stealing
- 性能は2番に近く、2番の欠点である不公平なスケジューリングの解決を図ったもの
- 個々のプロセッサがそれ専用の実行キューを持つが、プロセッサが暇になると他のプロセッサの実行キューからタスクを奪うタイプ
- 全てのタスクがほぼ公平にスケジューリングされる
- ほとんどの場合、実行キューが単一のプロセッサ(OSスレッド)からアクセスされるため、タスク切り替えのオーバーヘッドが低い
- 実装が複雑(ランタイムがバグりやすい)
単体テストコードはソースコードの中に書く。modでくくる
#[cfg(test)]
mod tests {
use super::add_two;
#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
}
結合テストはtests/
ディレクトリに格納する
https://doc.rust-lang.org/cargo/reference/environment-variables.html
FixtureTestは2019/07/12現在サポートされていない。
https://internals.rust-lang.org/t/pre-rfc-lightweight-test-fixtures/6605
type lookup xxx
https://qiita.com/yz2cm/items/9a8337c368cf055b4255#%E3%81%BE%E3%81%A8%E3%82%81%E3%82%8B%E3%81%A8
ない模様
https://github.com/rust-lang/rfcs/issues/1362
https://github.com/sagiegurari/cargo-make
let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
https://stackoverflow.com/questions/37792471/removing-elements-from-a-vec-based-on-some-condition
Utc::now().naive_utc()
let x: &'static str = "Hello, world.";
static Foo: i32 = 5;
let x: &'static i32 = &FOO;
引数処理
possible_valuesを使ってfrom_strで変換するのがよさげ
https://yuk1tyd.hatenablog.com/entry/2018/03/21/225533
https://totem3.hatenablog.jp/entry/2017/05/10/210000
aaa.as_ref() でOption<&T>に変換して、
aaa.as_ref().cloned() でOption
https://stackoverflow.com/questions/51338579/how-to-convert-optiont-to-optiont-in-the-most-idiomatic-way-in-rust
the trait std::error::Error
is not implemented for std::ffi::OsString
pathbuf.
.into_os_string()
.into_string()
.map_err(|x| format_err!("Home env not found {:?}", x))?)
boolinatorを使うのがよさそう
https://stackoverflow.com/questions/54841351/how-do-i-idiomatically-convert-a-bool-to-an-option-or-result-in-rust
fn trim_newline(s: &mut String) {
while s.ends_with('\n') || s.ends_with('\r') {
s.pop();
}
}
let len = input.trim_end_matches(&['\r', '\n'][..]).len();
input.truncate(len);
https://blog.v-gar.de/2019/04/rust-remove-trailing-newline-after-input/
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)
}
fast returnしたいときのやり方。closureに戻り値を書く
https://stackoverflow.com/questions/56535634/propagating-errors-from-within-a-closure-in-a-thread-in-rust
turbofish ::<>を使う
let _a = AAA::<i64>(0);
rustcにオプションをつける
-C opt-level=3 -C debug_assertions=no
by_ref()を使う
https://stackoverflow.com/questions/39935158/cannot-use-moved-bufreader-after-for-loop-with-bufreader-lines
let mut project_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
cargo build --verbose -vv
で表示できる。表示されないときはファイルを一部更新してもう一度実行してみる。
https://stackoverflow.com/questions/49077147/how-can-i-force-build-rs-to-run-again-without-cleaning-my-whole-project
std::fsのエラーメッセージは貧弱なのでex(https://docs.rs/ex/0.1.3/ex/)を使うとよい模様
https://www.reddit.com/r/rust/comments/bsn0zs/get_which_filename_is_not_found_on_rust_file/
1.26からはmainで?が使えるのでそれを使ったほうがいい。
https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
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(())
}
https://www.reddit.com/r/rust/comments/6c3gjr/early_return_and_if_let/
let _ = glob(glob_pattern)
.expect("Failed to read glob pattern")
.for_each(|path| fs::remove_file(path.as_ref().unwrap()).unwrap());
https://stackoverflow.com/questions/50458144/what-is-the-easiest-way-to-pad-a-string-with-0-to-the-left
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()?;
&str: std::error::Error
is not satisfied)format_err!()マクロを使う
ok_orを使う
env_loggerを使って、
env::set_var("RUST_LOG", "info");
let _ = env_logger::builder().is_test(true).try_init();
をsetupかなにかで毎回実行させる
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なら
[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(rename = "pos[0]")]
pos_0: Option<f64>,
をフィールドにつけてリネームする
https://serde.rs/container-attrs.html
struct Joeybloggs {
#[serde(rename(deserialize = "old", serialize = "new"))]
field: i32,
}
https://github.com/serde-rs/serde/issues/1320
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/test");
https://stackoverflow.com/questions/30003921/locating-resources-for-testing-with-cargo
{module-name}.rs or mod.rsにpub mod xxxの記述がないため実行ファイルからテストが呼び出せないことが原因。追加すること。
http://imoz.jp/note/rust-functions.html