🦀
The Rust Programing Language 6日目
前回のあらすじ
モジュールの分割方法、利用方法を学んだ
この辺結構感覚でやってしまってるので良く無いなあと反省
本日の学び
ベクタ
- これ競プロの解説とか読んでるとC++の実装でよく見る気がする
- リストみたいなもんかなと思ってた
-
let v: Vec<i32> = Vec::new();
- newするときは型注釈をつける
-
vec!
マクロで値つきで生成可能let v = vec![1, 2, 3];
- 値の追加は
push
- 当然
mut
にする必要がある
- 当然
- ベクタもスコープを抜ければ解放される
- 中身の要素も解放される
- ベクタの要素を読む
let v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; println!("The third element is {}", third); match v.get(2) { // "3つ目の要素は{}です" Some(third) => println!("The third element is {}", third), // "3つ目の要素はありません。" None => println!("There is no third element."), }
- 要素を得る方法は2つある
-
&v[2]
として要素の参照を取る- 無い添字を使うとパニックする
-
v.get(2)
として、Option<&T>
を取る- 無い添字を使ってもパニックせず、Noneが返る
-
- 要素を得る方法は2つある
- 要素が不変として借用されている時、要素を終端に追加することもできない
- 要素を追加するとき、連続したヒープ領域を確保できない際は新しいスペースへ移動するため
-
for i in &v
でループできるlet mut v = vec![100, 32, 57]; for i in &mut v { *i += 50; }
- 可変参照が参照している値を変更するためには、参照外し演算子
*
を使用する必要がある- よくわからないけど15章で追加解説があるらしいのでスルー
- 可変参照が参照している値を変更するためには、参照外し演算子
- Enumを経由して複数の肩を保持することができる
- 確かに〜
- 公式APIドキュメントを読もう!
文字列
- Rustには言語の核としては1種類しか文字列型が存在しない
- 文字列スライスtの
&str
- String型は、言語の核としてではなく標準ライブラリで提供される
- 標準ライブラリには他の文字列型も含まれる
- OsString, OsStr, CString, CStr etc..
- 文字列スライスtの
- 文字列生成
-
let mut s = String::new();
- 空の文字列を生成する
- あんまり使うことなさそう
- 空の文字列を生成する
- 文字列の初期値となるデータを
to_string
メソッドで変換let data = "initial contents"; let s = data.to_string(); // the method also works on a literal directly: let s = "initial contents".to_string();
-
let s = String::from("initial contents");
でも同じ- こっちのが楽なのでこっち使うのかな?
-
- 文字列の連結
-
+
演算子による連結let s1 = String::from("Hello, "); let s2 = String::from("world!"); let s3 = s1 + &s2; // s1はムーブされ、もう使用できないことに注意
-
+
演算子はadd
メソッドを使用するfn add(self, s: &str) -> String {
- 標準ライブラリでは
add
はジェネリクスで定義されている - これはString用のシグニチャ
- 上記の通りStringに追加できるのは
&str
のみだが、&String
を渡している- コンパイラが
&str
に型強制している
- コンパイラが
- selfは所有権をもらうので、後続で使用できないことに注意する
-
format!
マクロを使うと見やすく、所有権も奪わない
-
-
- Rustでは文字列に添字でアクセスできない
- 理由はいくつかあるが、簡単に言うと想定外のバグを防ぐため、パフォーマンスのためという感じっぽいです(諦め)
- スライスはできるが、パニックさせることが起こりやすいので注意する
- あまりしない方が良さそうだけど、文字列の切り出しはどうするのだろう
- クレート使うことになりそう
- あまりしない方が良さそうだけど、文字列の切り出しはどうするのだろう
ハッシュマップ
-
HashMap
は初期化処理でスコープに入らないので、use
する必要がある - 生成マクロも存在しない
- タプルのベクタに対して
collect
メソッドを使って生成できるuse std::collections::HashMap; let teams = vec![String::from("Blue"), String::from("Yellow")]; let initial_scores = vec![10, 50]; let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
- collectは色々なデータ構造にまとめられるので、
HashMap<_, _>
として指定する- ベクタの中身からデータ型については推論できる
- collectは色々なデータ構造にまとめられるので、
-
insert
でmapに挿入すると、所有権はムーブする -
get(Key)
で値を取り出せる-
Option<&V>
を返す
-
-
for (key, value) in &scores {
の様にループできる - 同様のkeyをinsertすると、値は上書きされる
-
entry API
を使って、「まだ無ければ挿入」ができるuse std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.entry(String::from("Yellow")).or_insert(50); scores.entry(String::from("Blue")).or_insert(50); println!("{:?}", scores);
- 元の値を利用して値を更新する
use std::collections::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; } println!("{:?}", map);
-
or_insert
は値への可変参照を返すので、参照外しして更新できる
-
- 標準の
HashMap
はパフォーマンスを落として安全性を得ている- 気に食わなければ外部クレートを使えば良い
本日のまとめ
ベクタ、まあリストだなと思ったけどちょいちょい考えないといけないことが多そうな感じがした
HashMapについては結構すんなり使えそう
文字列の扱いで困ること今後ありそうだなーと強く思ったので、楽しみにしておく
Discussion