チュートリアル

Rust基礎:コレクション

Rust入門コレクション
広告エリア

配列

固定長のコレクションです。

// 配列の宣言
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 5];  // [0, 0, 0, 0, 0]

// 要素へのアクセス
println!("{}", numbers[0]);  // 1
println!("{}", numbers.len());  // 5

// スライス
let slice = &numbers[1..3];  // [2, 3]

// イテレート
for num in &numbers {
    println!("{}", num);
}

Vec(ベクタ)

可変長のコレクションです。

// 作成
let mut vec: Vec<i32> = Vec::new();
let vec2 = vec![1, 2, 3];  // マクロで作成

// 追加
vec.push(1);
vec.push(2);
vec.push(3);

// 取得
println!("{}", vec[0]);  // 1
println!("{:?}", vec.get(10));  // None(安全なアクセス)

// 更新
vec[0] = 10;

// 削除
vec.pop();  // 末尾を削除
vec.remove(0);  // インデックスで削除

// 長さと容量
println!("長さ: {}", vec.len());
println!("容量: {}", vec.capacity());

// イテレート
for num in &vec {
    println!("{}", num);
}

// 変更しながらイテレート
for num in &mut vec {
    *num *= 2;
}

Vec の操作

let mut numbers = vec![3, 1, 4, 1, 5, 9, 2, 6];

// ソート
numbers.sort();
println!("{:?}", numbers);  // [1, 1, 2, 3, 4, 5, 6, 9]

// 逆順
numbers.reverse();

// 検索
let found = numbers.contains(&5);
let position = numbers.iter().position(|&x| x == 5);

// スライス
let slice = &numbers[0..3];

// 結合
let mut a = vec![1, 2];
let mut b = vec![3, 4];
a.append(&mut b);

// フィルタリング
let evens: Vec<i32> = numbers.into_iter().filter(|x| x % 2 == 0).collect();

String

UTF-8エンコードされた文字列です。

// 作成
let mut s = String::new();
let s2 = String::from("Hello");
let s3 = "World".to_string();

// 追加
s.push_str("Hello");
s.push(' ');
s.push_str("World");

// 連結
let hello = String::from("Hello");
let world = String::from("World");
let hello_world = hello + " " + &world;  // helloは移動

// format!マクロ
let s = format!("{} {}", "Hello", "World");

// スライス
let hello = &s[0..5];

// 長さ
println!("バイト数: {}", s.len());
println!("文字数: {}", s.chars().count());

// イテレート
for c in s.chars() {
    println!("{}", c);
}

文字列操作

let text = "  Hello, World!  ";

// トリム
let trimmed = text.trim();

// 分割
let words: Vec<&str> = text.split(',').collect();

// 検索
let contains = text.contains("World");
let starts = text.starts_with("  H");
let ends = text.ends_with("!  ");

// 置換
let replaced = text.replace("World", "Rust");

// 大文字・小文字
let upper = text.to_uppercase();
let lower = text.to_lowercase();

HashMap

キーと値のペアを格納します。

use std::collections::HashMap;

// 作成
let mut scores: HashMap<String, i32> = HashMap::new();

// 追加
scores.insert(String::from("太郎"), 85);
scores.insert(String::from("花子"), 92);

// 取得
let score = scores.get("太郎");
match score {
    Some(s) => println!("太郎: {}", s),
    None => println!("見つかりません"),
}

// 存在しない場合のみ挿入
scores.entry(String::from("次郎")).or_insert(78);

// 更新
scores.insert(String::from("太郎"), 90);

// 削除
scores.remove("花子");

// イテレート
for (key, value) in &scores {
    println!("{}: {}", key, value);
}

HashMap の応用

use std::collections::HashMap;

// 単語カウント
fn word_count(text: &str) -> HashMap<String, i32> {
    let mut counts = HashMap::new();
    for word in text.split_whitespace() {
        let count = counts.entry(word.to_lowercase()).or_insert(0);
        *count += 1;
    }
    counts
}

let text = "hello world hello rust hello";
let counts = word_count(text);
for (word, count) in &counts {
    println!("{}: {}", word, count);
}

HashSet

重複のない値の集合です。

use std::collections::HashSet;

let mut set: HashSet<i32> = HashSet::new();

// 追加
set.insert(1);
set.insert(2);
set.insert(2);  // 重複は無視

println!("{}", set.len());  // 2

// 存在確認
println!("{}", set.contains(&1));  // true

// 削除
set.remove(&1);

// 集合演算
let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
let b: HashSet<_> = [3, 4, 5].iter().cloned().collect();

// 和集合
let union: HashSet<_> = a.union(&b).cloned().collect();

// 積集合
let intersection: HashSet<_> = a.intersection(&b).cloned().collect();

// 差集合
let difference: HashSet<_> = a.difference(&b).cloned().collect();

イテレータ

let numbers = vec![1, 2, 3, 4, 5];

// iter() - 不変参照
for n in numbers.iter() {
    println!("{}", n);
}

// iter_mut() - 可変参照
let mut numbers = vec![1, 2, 3];
for n in numbers.iter_mut() {
    *n *= 2;
}

// into_iter() - 所有権を取得
let numbers = vec![1, 2, 3];
for n in numbers.into_iter() {
    println!("{}", n);
}
// numbers はここでは使えない

// イテレータアダプタ
let sum: i32 = (1..=100)
    .filter(|n| n % 2 == 0)  // 偶数のみ
    .map(|n| n * n)          // 二乗
    .take(10)                // 最初の10個
    .sum();                  // 合計

実践例:学生成績管理

use std::collections::HashMap;

#[derive(Debug)]
struct Student {
    name: String,
    scores: Vec<i32>,
}

impl Student {
    fn new(name: &str) -> Self {
        Student {
            name: name.to_string(),
            scores: Vec::new(),
        }
    }

    fn add_score(&mut self, score: i32) {
        self.scores.push(score);
    }

    fn average(&self) -> f64 {
        if self.scores.is_empty() {
            return 0.0;
        }
        self.scores.iter().sum::<i32>() as f64 / self.scores.len() as f64
    }
}

fn main() {
    let mut students: HashMap<String, Student> = HashMap::new();

    // 学生を追加
    students.insert("S001".to_string(), Student::new("太郎"));
    students.insert("S002".to_string(), Student::new("花子"));

    // 成績を追加
    if let Some(student) = students.get_mut("S001") {
        student.add_score(85);
        student.add_score(90);
        student.add_score(78);
    }

    if let Some(student) = students.get_mut("S002") {
        student.add_score(92);
        student.add_score(88);
    }

    // 結果を表示
    for (id, student) in &students {
        println!("{} ({}): 平均 {:.1}点",
            student.name, id, student.average());
    }
}

まとめ

  • 配列[T; N]は固定長、Vec<T>は可変長
  • StringはUTF-8文字列、&strは文字列スライス
  • HashMap<K, V>でキーと値のペア
  • HashSet<T>で重複なしの集合
  • iter(), iter_mut(), into_iter()でイテレート
  • イテレータアダプタで関数型スタイル

次回は構造体について学びます。

広告エリア