본문 바로가기

Rust

[Rust] 컬렉션 (Collection)

https://www.pexels.com/ko-kr/photo/159711/

 

안녕하세요

오늘은 Rust의 Collection에 대해 알아보도록 하겠습니다


📌 컬렉션

Rust의 컬렉션은 대부분 std::collections 모듈에 정의돼 있습니다

 

주요 컬렉션 타입으로는 다음과 같습니다

타입 설명 특징
Vec<T> 가변 크기 배열 (Vector) 요소를 동적으로 추가 가능
String 유니코드 문자열 Vec<u8> 기반
HashMap<K, V> 키-값 쌍 저장 해시 기반, 빠른 검색
HashSet<T> 중복 없는 값 저장 내부적으로 HashMap<T, ()>
LinkedList<T> 양방향 연결 리스트 요소의 앞뒤 삽입에 효율적
VecDeque<T> 양쪽에서 push/pop 가능 큐처럼 사용 가능
BinaryHeap<T> 우선순위 큐 최대 힙 구조
BTreeMap<K, V> 정렬된 키-값 저장 트리 기반 (순회 순서 보장)
BTreeSet<T> 정렬된 중복 없는 값 BTreeMap<T, ()> 기반

 


📌 Vec<T>

Vec<T>는 가변 크기의 배열입니다

→ 크기를 동적으로 관리하는 컬렉션 입니다

 

✅ 생성

Vec::new() 또는 vec! 을 사용해서 Vector를 만들 수 있습니다

let v: Vec<i32> = Vec::new(); // 빈 벡터 생성
let v = vec![1, 2, 3]; // 초기값을 가진 벡터 생성

 

✅ 요소 추가 및 읽기

get 또는 []을 사용해 벡터 안의 값을 읽을 수 있습니다

  • v.get(2) : 존재하지 않으면 None
  • v[2] : 존재하지 않으면 panic!
fn main() {
    let mut v = Vec::new(); // 타입 추론도 가능

    v.push(10);
    v.push(20);
    v.push(30);

    println!("첫 번째 값: {}", v[0]);
    println!("세 번째 값: {}", v.get(2).unwrap()); // 안전하게 접근
}

 

✅ 반복문

벡터의 요소를 순회하기 위해 반복문을 사용할 수도 있습니다

fn main() {
    let mut v = Vec::new();
    v.push(10);

    for x in &v {
        println!("{}", x);
    }
}

 

✅ 소유권

벡터는 값을 소유하고 있습니다

→ 값이 이동하면 원래 벡터는 그 값을 더 이상 사용할 수 없습니다

fn main() {
    let mut v = vec![String::from("hello")];

    let s = v.pop().unwrap(); // s는 "hello"를 가져감 (move)
    println!("{}", s); // hello
    // println!("{}", v[0]); // ❌ 에러: 값이 이미 이동됨
}

📌 HashMap<K, V>

HashMap<K, V>는 키-값 쌍을 저장하는 자료구조 입니다

 

✅ 생성 및 사용법

HashMap::new()를 통해 생성하고,

insert와 get으로 write/read 할 수 있습니다

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert("apple", 3);
    map.insert("banana", 5);

    println!("apple: {:?}", map.get("apple")); // Some(3)
    println!("kiwi: {:?}", map.get("kiwi"));   // None
}

 

✅ entry()와 or_insert()

특정 키가 없어 default 값을 넣고 싶은 경우에 사용할 수 있습니다

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert("Rust", 1);

    // 값이 없으면 0을 넣고 그 참조를 반환
    let count = map.entry("Go").or_insert(0);
    *count += 1;

    println!("{:?}", map); // {"Rust": 1, "Go": 1}
}

 

✅ 소유권

insert()는 값과 키를 소유합니다

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    let name = String::from("Alice");

    map.insert(name, 10);
    println!("{}", name); // name은 move 됐기 때문에 여기서 사용 불가
}

 

✅ vs BTreeMap

BTreeMap은 정렬이 필요할 때 사용합니다

use std::collections::{HashMap, BTreeMap};

fn main() {
    let mut hmap = HashMap::new();
    hmap.insert(3, "three");
    hmap.insert(1, "one");
    hmap.insert(2, "two");

    println!("HashMap:");
    for (k, v) in &hmap {
        println!("{k}: {v}"); // 순서 보장 ❌
    }

    let mut bmap = BTreeMap::new();
    bmap.insert(3, "three");
    bmap.insert(1, "one");
    bmap.insert(2, "two");

    println!("\nBTreeMap:");
    for (k, v) in &bmap {
        println!("{k}: {v}"); // 순서 보장 ✅
    }
}

📌 HashSet<T>

HashSet<T>는 중복 없는 값들의 집합을 표현하는 자료구조 입니다

 

✅ 생성 및 사용법

HashSet::new()로 생성하며,

insert와 contains 등을 사용할 수 있습니다

use std::collections::HashSet;

fn main() {
    let mut set = HashSet::new();

    set.insert("apple");
    set.insert("banana");
    set.insert("apple"); // 중복 삽입 → 무시됨

    println!("set contains apple? {}", set.contains("apple")); // true
    println!("set size: {}", set.len()); // 2

    set.remove("banana");
    println!("{:?}", set); // {"apple"}
}

 

✅ 집합 연산 메서드

수학의 집합처럼 다룰 수 있는 메서드도 있습니다

use std::collections::HashSet;

fn main() {
    let a: HashSet<_> = [1, 2, 3].into_iter().collect();
    let b: HashSet<_> = [3, 4, 5].into_iter().collect();

    // 합집합
    let union: HashSet<_> = a.union(&b).copied().collect();
    println!("합집합: {:?}", union); // {1, 2, 3, 4, 5}

    // 교집합
    let intersection: HashSet<_> = a.intersection(&b).copied().collect();
    println!("교집합: {:?}", intersection); // {3}

    // 차집합
    let difference: HashSet<_> = a.difference(&b).copied().collect();
    println!("차집합 (a - b): {:?}", difference); // {1, 2}

    // 대칭 차집합
    let sym_diff: HashSet<_> = a.symmetric_difference(&b).copied().collect();
    println!("대칭 차집합: {:?}", sym_diff); // {1, 2, 4, 5}
}

📌 VecDeque<T>

VecDeque<T>는 Double-Ended Queue (양방향 큐) 를 구현한 자료구조 입니다

front, back 양쪽에서 빠르게 push / pop 할 수 있습니다

 

✅ 생성 및 사용법

VecDeque::new()로 생성하고

push_back, pop_front 등을 사용할 수 있습니다

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); // [0, 1, 2]

    let front = deque.pop_front();
    let back = deque.pop_back();

    println!("front: {:?}, back: {:?}", front, back); // Some(0), Some(2)
    println!("now: {:?}", deque); // [1]
}