📦
컬렉션 — 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>으로 타입 안전하게