Step 05: 컬렉션과 반복자
core 60 min

컬렉션과 반복자

Vec, HashMap을 사용하고 반복자로 데이터를 처리합니다.

Execute this step

Run from project root:
cargo run

Step 5: 컬렉션과 반복자

학습 목표

  • Vec<T>로 가변 길이 배열 다루기
  • 반복자로 함수형 프로그래밍 스타일 사용하기
  • filter, map, collect로 데이터 변환하기

핵심 개념

1. Vec<T> 기초

1fn main() {
2    // 빈 벡터 생성
3    let mut v1: Vec<i32> = Vec::new();
4    v1.push(1);
5    v1.push(2);
6    
7    // 매크로로 생성
8    let v2 = vec![1, 2, 3, 4, 5];
9    
10    // 인덱스 접근
11    let third = v2[2];
12    println!("세 번째 원소: {}", third);
13    
14    // get 메서드 (Option 반환)
15    match v2.get(2) {
16        Some(third) => println!("세 번째 원소: {}", third),
17        None => println!("없음"),
18    }
19}

2. for 루프

1fn main() {
2    let v = vec![1, 2, 3];
3    
4    // 불변 반복
5    for i in &v {
6        println!("{}", i);
7    }
8    
9    // 가변 반복
10    let mut v2 = vec![1, 2, 3];
11    for i in &mut v2 {
12        *i += 10; // 역참조 후 수정
13    }
14}

3. 반복자 (Iterator)

Rust의 반복자는 lazy합니다. 실제로 사용될 때까지 계산하지 않습니다.

1fn main() {
2    let v = vec![1, 2, 3, 4, 5];
3    
4    // 반복자 메서드 체이닝
5    let doubled: Vec<_> = v.iter()
6        .map(|x| x * 2)      // 각 원소에 2 곱하기
7        .filter(|x| x > &5)  // 5보다 큰 것만
8        .collect();          // Vec으로 수집
9    
10    println!("{:?}", doubled); // [6, 8, 10]
11}

4. 주요 반복자 메서드

1let v = vec![1, 2, 3, 4, 5];
2
3// map: 변환
4let doubled: Vec<_> = v.iter().map(|x| x * 2).collect();
5
6// filter: 필터링
7let even: Vec<_> = v.iter().filter(|x| *x % 2 == 0).collect();
8
9// find: 첫 번째 일치하는 원소
10let first_even = v.iter().find(|x| *x % 2 == 0);
11
12// any: 조건을 만족하는 원소가 하나라도 있는지
13let has_even = v.iter().any(|x| x % 2 == 0);
14
15// count: 개수
16let count = v.iter().filter(|x| *x > 2).count();

Library에 검색 기능 추가

1impl Library {
2    // 카테고리별 검색
3    fn list_by_category(&self, category: Category) -> Vec<&Book> {
4        self.books.values()
5            .filter(|book| matches!(book.category, category))
6            .collect()
7    }
8    
9    // 대여 가능한 책만
10    fn list_available(&self) -> Vec<&Book> {
11        self.books.values()
12            .filter(|book| matches!(book.status, BookStatus::Available))
13            .collect()
14    }
15    
16    // 제목으로 검색
17    fn search_by_title(&self, keyword: &str) -> Vec<&Book> {
18        self.books.values()
19            .filter(|book| book.title.contains(keyword))
20            .collect()
21    }
22    
23    // 저자로 검색
24    fn search_by_author(&self, keyword: &str) -> Vec<&Book> {
25        self.books.values()
26            .filter(|book| book.author.contains(keyword))
27            .collect()
28    }
29    
30    // 통계
31    fn get_statistics(&self) {
32        let total = self.books.len();
33        let available = self.list_available().len();
34        let borrowed = self.books.values()
35            .filter(|book| matches!(book.status, BookStatus::Borrowed { .. }))
36            .count();
37        
38        println!("\n=== 도서관 통계 ===");
39        println!("전체 도서: {}권", total);
40        println!("대여 가능: {}권", available);
41        println!("대여 중: {}권", borrowed);
42        
43        // 카테고리별 통계
44        println!("\n카테고리별:");
45        let categories = [Category::Fiction, Category::NonFiction, Category::Science, Category::History];
46        for cat in &categories {
47            let count = self.list_by_category(*cat).len();
48            if count > 0 {
49                let name = match cat {
50                    Category::Fiction => "소설",
51                    Category::NonFiction => "비소설",
52                    Category::Science => "과학",
53                    Category::History => "역사",
54                };
55                println!("  {}: {}권", name, count);
56            }
57        }
58    }
59}

전체 예제

1fn main() {
2    println!("=== 도서 관리 시스템 v0.5 ===\n");
3    
4    let mut library = Library::new();
5    
6    // 여러 책 추가
7    let books = vec![
8        ("러스트 프로그래밍", "스티브", Category::Science),
9        ("클린 코드", "로버트 마틴", Category::NonFiction),
10        ("해리포터", "J.K. 롤링", Category::Fiction),
11        ("반지의 제왕", "톨킨", Category::Fiction),
12        ("사피엔스", "유발 하라리", Category::History),
13        ("코스모스", "칼 세이건", Category::Science),
14    ];
15    
16    for (title, author, category) in books {
17        library.add_book(title.to_string(), author.to_string(), category);
18    }
19    
20    // 전체 목록
21    library.list_all();
22    
23    // 통계
24    library.get_statistics();
25    
26    println!();
27    
28    // 책 대여
29    library.borrow_book(1, String::from("김철수"), String::from("2026-02-20")).ok();
30    library.borrow_book(3, String::from("이영희"), String::from("2026-02-22")).ok();
31    library.borrow_book(5, String::from("박민수"), String::from("2026-02-25")).ok();
32    
33    // 카테고리별 검색
34    println!("\n=== 소설 도서 ===");
35    let fiction_books = library.list_by_category(Category::Fiction);
36    for book in &fiction_books {
37        book.display();
38    }
39    println!("총 {}권", fiction_books.len());
40    
41    // 대여 가능한 책
42    println!("\n=== 대여 가능한 책 ===");
43    let available = library.list_available();
44    for book in &available {
45        book.display();
46    }
47    println!("총 {}권", available.len());
48    
49    // 제목 검색
50    println!("\n=== '프로그래밍' 검색 ===");
51    let results = library.search_by_title("프로그래밍");
52    for book in &results {
53        book.display();
54    }
55    println!("총 {}권", results.len());
56    
57    // 저자 검색
58    println!("\n=== '롤링' 검색 ===");
59    let results = library.search_by_author("롤링");
60    for book in &results {
61        book.display();
62    }
63    println!("총 {}권", results.len());
64    
65    // 최종 통계
66    library.get_statistics();
67}

matches! 매크로

matches!는 패턴 매칭 결과를 bool로 반환합니다.

1let status = BookStatus::Available;
2
3// match 사용
4let is_available = match status {
5    BookStatus::Available => true,
6    _ => false,
7};
8
9// matches! 사용 (더 간결)
10let is_available = matches!(status, BookStatus::Available);

체크리스트

  • [ ] Vec<T>를 생성하고 사용했습니다
  • [ ] for 루프로 벡터를 순회했습니다
  • [ ] 반복자 메서드(iter, filter, map, collect)를 사용했습니다
  • [ ] matches! 매크로를 사용했습니다
  • [ ] 검색과 필터링 기능을 구현했습니다

다음 단계

Step 6에서는 파일 I/O로 데이터를 저장하고 불러오는 기능을 추가합니다. 축하합니다! 이제 Rust 초급 과정을 거의 완료했습니다!

Did you find this helpful? Give it a cheer!