📦

컬렉션 — Array와 Hash가 Vec과 HashMap이 되면

타입이 고정된 세계의 배열과 해시맵

Vec — Ruby의 Array

# Ruby — 아무 타입이나 섞어 넣을 수 있다
arr = [1, "hello", true, nil]

// Rust — 한 가지 타입만
let arr: Vec<i32> = vec![1, 2, 3];
// vec![1, "hello"]  // 컴파일 에러

기본 조작:

let mut v = vec![1, 2, 3];
v.push(4);              // Ruby: arr.push(4) / arr << 4
v.pop();                // Ruby: arr.pop
v.len();                // Ruby: arr.length
v[0];                   // Ruby: arr[0]
v.contains(&3);         // Ruby: arr.include?(3)
v.is_empty();           // Ruby: arr.empty?

HashMap — Ruby의 Hash

# Ruby
h = { name: "sehwa", age: 30 }
h[:name]  # "sehwa"

// Rust
use std::collections::HashMap;

let mut h = HashMap::new();
h.insert("name", "sehwa");
h.insert("age", "30");  // 값도 같은 타입이어야 함

h.get("name");  // Option<&&str> — 없으면 None (nil 아님!)

Ruby에서 h[:missing]은 nil을 반환한다. Rust에서 h.get("missing")None을 반환한다. Option 처리가 필요.

entry API — Ruby의 Hash.new(default)에 대응

Ruby에서 Hash.new(0)으로 기본값을 설정하는 패턴이 있다. Rust에서는 entry API가 이 역할.

# Ruby
counts = Hash.new(0)
words.each { |w| counts[w] += 1 }

// Rust
let mut counts = HashMap::new();
for word in &words {
    *counts.entry(word).or_insert(0) += 1;
}

entry().or_insert(0)는 "키가 없으면 0을 넣고, 있든 없든 그 값의 가변 참조를 반환"이다.

HashSet — Ruby의 Set

# Ruby
require 'set'
s = Set.new([1, 2, 3])
s.include?(2)  # true

// Rust
use std::collections::HashSet;
let s: HashSet<i32> = [1, 2, 3].iter().cloned().collect();
s.contains(&2);  // true

정렬

# Ruby
[3, 1, 2].sort                    # [1, 2, 3]
users.sort_by { |u| u.age }       # 필드로 정렬

// Rust
let mut v = vec![3, 1, 2];
v.sort();                          // [1, 2, 3]
users.sort_by(|a, b| a.age.cmp(&b.age));  // 필드로 정렬

Rust의 sort()원본을 변경한다(mut 필요). 원본 유지하려면 .clone()한 뒤 정렬.

타입이 하나라는 제약

Ruby의 [1, "hello", true]가 안 된다. 여러 타입을 담고 싶으면 enum을 쓴다.

enum Value {
    Int(i32),
    Str(String),
    Bool(bool),
}
let mixed: Vec<Value> = vec![
    Value::Int(1),
    Value::Str("hello".into()),
    Value::Bool(true),
];

번거롭지만, 꺼낼 때 타입 체크가 강제되니 런타임 에러가 줄어든다.

핵심 포인트

1

Array → Vec<T>, Hash → HashMap<K, V> — 타입 파라미터 필수

2

Hash.get()은 Option 반환 — nil 대신 None

3

entry().or_insert()로 기본값 패턴 구현

4

여러 타입을 담으려면 enum으로 래핑

장점

  • 타입이 고정되어 있어서 꺼낼 때 형변환이 불필요하다
  • get()이 Option 반환이라 인덱스 에러가 없다

단점

  • Ruby의 유연한 배열 조작에 비해 타입 제약이 불편하다
  • HashMap 초기화가 Ruby Hash 리터럴보다 장황하다

사용 사례

데이터 그룹핑/카운팅 — HashMap + entry 패턴 API 응답 데이터 파싱 — Vec<Item>으로 타입 안전하게