Step 05: 컬렉션과 반복자
0 studying now
core 60 min
컬렉션과 반복자
Vec, HashMap을 사용하고 반복자로 데이터를 처리합니다.
Execute this step
Run from project root:
cargo runStep 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 초급 과정을 거의 완료했습니다!