HashMap
let text = "hello world wonderful world"; let mut map = HashMap::new(); for word in text.split_whitespace() { let count = map.entry(word).or_insert(0); *count += 1; }
これはtextに記載されている文字列から空白を削除して、単語を数える処理。 word変数がキーになり、count変数が出現数になる。 初めにcount=0を代入して、出現するたびにcountを+1していく。
panic
この記述でpanicを呼び出せる。
panic!("crash and burn");
RUST_BACKTRACE=1を入力して実行すると、panicになるまでの関数が使われた関数がわかる。
RUST_BACKTRACE=1 cargo run
全然関係ないがmatch関数を使うとファイルが存在しなときに自動で作成してくれたりして便利。
fn file_open_error() { let f = File::open("hello.txt"); let f = match f { Ok(file) => file, Err(ref error) if error.kind() == ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, Err(e) => { panic!("Tried to create file but there was a problem: {:?}", e) } }, Err(error) => { panic!("There was a problem opening the file: {:?}", error) } }; }
expect関数はpanic!のエラーメッセージをこちらで決められる。
let f = File::open("hello2.txt").expect("Failed to open hello2.txt");
ファイルを開けたら→ファイルの中身を読み込む一連の処理を書き方次第で短くできる。
第一段階(match処理で愚直に分岐を書く)
fn read_username_from_file() -> Result<String, io::Error> { let f = File::open("hello2.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } }
第二段階(?を使ってエラーかどうかを確認する)
fn read_username_from_file2() -> Result<String, io::Error> { let mut f = File::open("hello.txt"); let mut s = String::new(); f.read_to_string(&mut s)?; Ok(s) }
第三段階(?を二つ使ってオープンの判定と記載の判定をする。ここまでくると呪文。可読性はよいのだろうか?)
fn read_username_from_file3() -> Result<String, io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) }
panic!使う前にまずResultで返すことを念頭に置いて設計するといいらしい。
ジェネリクス
値の型が一つのときは、
struct Point2<T> { x: T, y: T, }
値の型が二つあるときは、
struct Point<T, U> { x: T, y: U, }
値が増えたらメンテナンスが大変そうだから、長くなった場合はソースを見直す必要がある。