概要
コレクション型は、複数のデータを効率的に管理するためのデータ構造である。
Rustのコレクション型は、ヒープ上にデータを格納し、コンパイル時にサイズが決まっていなくても使用できる。
用途に応じて適切なコレクション型を選択することで、効率的なプログラムを作成することができる。
コレクション型の選択
用途に応じて適切なコレクション型を選択することが重要である。
- 順序付きリスト
- Vec<T>
- キー・値の検索
- HashMap<K, V>
- 重複排除
- HashSet<T>
- 両端操作
- VecDeque<T>
- ソート済み
- BTreeMap<K, V> / BTreeSet<T>
- 優先度管理
- BinaryHeap<T>
Vec<T> : 可変長配列
Vec<T>は、動的にサイズが変わる配列型である。
連続したメモリ領域に要素を格納し、インデックスによる高速なアクセスが可能である。
順序付きリストが必要な場合に使用する。
fn main() {
let mut v = vec![1, 2, 3];
v.push(4);
v.push(5);
println!("{:?}", v);
// インデックスでアクセス
println!("{}", v[0]);
// 要素の削除
v.pop();
println!("{:?}", v);
}
// 出力
[1, 2, 3, 4, 5]
1
[1, 2, 3, 4]
HashMap<K, V> : ハッシュマップ
HashMap<K, V>は、キーと値のペアを格納するコレクション型である。
キーを指定することで、対応する値を高速に検索できる。
キーと値の検索が必要な場合に使用する。
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Blue", 10);
scores.insert("Red", 50);
// 値の取得
let score = scores.get("Blue");
println!("{:?}", score);
// キーが存在するか確認
if scores.contains_key("Blue") {
println!("Blue team exists");
}
// 全要素の走査
for (key, value) in &scores {
println!("{}: {}", key, value);
}
}
// 出力
Some(10)
Blue team exists
Blue: 10
Red: 50
HashSet<T> : ハッシュセット
HashSet<T>は、重複のない値の集合を表すコレクション型である。
値の存在確認が高速に行うことができるる。
重複を排除する場合に使用する。
use std::collections::HashSet;
fn main() {
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(2); // 重複は無視される
println!("{:?}", set);
// 値の存在確認
if set.contains(&1) {
println!("1 is in the set");
}
// 要素数
println!("Size: {}", set.len());
}
// 出力
{1, 2}
1 is in the set
Size: 2
VecDeque<T> : 両端キュー
VecDeque<T>は、先頭と末尾の両方から効率的に要素を追加・削除できるコレクション型である。
両端操作が頻繁に必要な場合に使用する。
use std::collections::VecDeque;
fn main() {
let mut deque = VecDeque::new();
// 末尾に追加
deque.push_back(1);
deque.push_back(2);
// 先頭に追加
deque.push_front(0);
println!("{:?}", deque);
// 先頭から削除
deque.pop_front();
// 末尾から削除
deque.pop_back();
println!("{:?}", deque);
}
// 出力
[0, 1, 2]
[1]
BTreeMap<K, V> / BTreeSet<T> : ソート済みマップ・セット
BTreeMap<K, V>とBTreeSet<T>は、キーがソートされた状態で保持されるコレクション型である。
順序付きの走査が必要な場合や、範囲検索を行いたい場合に使用する。
use std::collections::BTreeMap;
fn main() {
let mut map = BTreeMap::new();
map.insert(3, "three");
map.insert(1, "one");
map.insert(2, "two");
// キーがソートされた順で出力される
for (key, value) in &map {
println!("{}: {}", key, value);
}
}
// 出力
1: one
2: two
3: three
use std::collections::BTreeSet;
fn main() {
let mut set = BTreeSet::new();
set.insert(5);
set.insert(1);
set.insert(3);
// ソートされた順で出力される
for value in &set {
println!("{}", value);
}
}
// 出力
1
3
5
BinaryHeap<T> : 優先度キュー
BinaryHeap<T>は、最大値を効率的に取り出せる優先度キューである。
優先度管理が必要な場合に使用する。
use std::collections::BinaryHeap;
fn main() {
let mut heap = BinaryHeap::new();
heap.push(3);
heap.push(1);
heap.push(5);
heap.push(2);
// 最大値から順に取り出される
while let Some(value) = heap.pop() {
println!("{}", value);
}
}
// 出力
5
3
2
1
LinkedList<T> : 連結リスト
LinkedList<T>は、双方向連結リストである。
実際の使用では、Vec<T>の方が効率的なことが多いため、あまり使用されない。
use std::collections::LinkedList;
fn main() {
let mut list = LinkedList::new();
list.push_back(1);
list.push_back(2);
list.push_front(0);
println!("{:?}", list);
}
// 出力
[0, 1, 2]
文字列型
String : 所有権を持つ文字列
Stringは、所有権を持つ可変長の文字列型である。
文字列の内容を変更する必要がある場合に使用する。
fn main() {
let mut s = String::from("hello");
s.push_str(" world");
println!("{}", s);
}
// 出力
hello world
&str : 文字列スライス
&strは、文字列への参照を表す型である。
文字列を読み取るだけで変更しない場合に使用する。
fn main() {
let s: &str = "hello";
println!("{}", s);
}
// 出力
hello
Option型とResult型
Option<T> : 値があるかないか
Option<T>は、値が存在するかしないかを表す型である。
Some(value)で値がある状態、Noneで値がない状態を表す。
fn main() {
let some_number = Some(5);
let no_number: Option<i32> = None;
match some_number {
Some(n) => println!("Number: {}", n),
None => println!("No number"),
}
match no_number {
Some(n) => println!("Number: {}", n),
None => println!("No number"),
}
}
// 出力
Number: 5
No number
Result<T, E> : 成功または失敗
Result<T, E>は、処理の成功または失敗を表す型である。
Ok(value)で成功、Err(error)で失敗を表す。
これは、エラー処理が必要な場合に使用する。
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("division by zero"))
}
else {
Ok(a / b)
}
}
fn main() {
match divide(10, 2) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
match divide(10, 0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}
// 出力
Result: 5
Error: division by zero
共通のメソッド
lenメソッドで要素数を取得する
多くのコレクション型は、lenメソッドで要素数を取得することができる。
fn main() {
let v = vec![1, 2, 3, 4, 5];
println!("Length: {}", v.len());
}
// 出力
Length: 5
is_emptyメソッドで空かどうか確認する
コレクションが空かどうかを確認するには、is_empty メソッドを使用する。
fn main() {
let v: Vec<i32> = Vec::new();
println!("Is empty: {}", v.is_empty());
let v2 = vec![1, 2, 3];
println!("Is empty: {}", v2.is_empty());
}
// 出力
Is empty: true
Is empty: false
clear関数で全要素を削除する
コレクションの全要素を削除するには、clear メソッドを使用する。
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
println!("Before: {:?}", v);
v.clear();
println!("After: {:?}", v);
}
// 出力
Before: [1, 2, 3, 4, 5]
After: []