Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

클로저와 반복자: LINQ를 넘어서는 성능과 유연성

학습 목표: Rust의 **클로저(Closures)**가 소유권을 어떻게 다루는지 배우고, C#의 LINQ에 대응하는 **반복자(Iterators)**를 마스터합니다. '제로 비용 추상화'를 통해 함수형 프로그래밍의 편리함과 네이티브 루프의 성능을 동시에 잡는 비결을 익힙니다.


1. 클로저: 소유권을 인식하는 익명 함수

C#의 람다는 외부 변수를 항상 참조로 캡처하지만, Rust는 상황에 따라 빌림이나 **이동(Move)**을 선택할 수 있습니다.

  • Fn: 데이터를 불변으로 빌려옵니다. 여러 번 호출 가능합니다.
  • FnMut: 데이터를 가변으로 빌려와 수정합니다. 여러 번 호출 가능합니다.
  • FnOnce: 데이터의 소유권을 가져갑니다. 딱 한 번만 호출할 수 있습니다.
#![allow(unused)]
fn main() {
// [move 클로저 예시]
let data = vec![1, 2, 3];
let handle = thread::spawn(move || {
    // data의 소유권이 스레드 내부로 이동됨
    println!("{:?}", data);
});
}

2. 반복자(Iterator): Rust의 LINQ

Rust의 반복자는 C#의 LINQ와 매우 흡사한 선언적 문법을 제공합니다. 하지만 런타임 오버헤드가 있는 LINQ와 달리, Rust 반복자는 최적화된 for 루프와 동일한 성능을 냅니다.

비교 항목C# (LINQ)Rust (Iterator)
평가 방식지연 평가 (Lazy)지연 평가 (Lazy)
성능 오버헤드가상 호출, 할당 발생 가능제로 비용 (인라인화됨)
추상화 단위IEnumerable<T>Iterator 트레이트
최종 수집.ToList(), .ToArray().collect::<Vec<_>>()

3. 주요 연산자 매핑

LINQRust Iterator비고
.Select(x => ...)`.map(x
.Where(x => ...)`.filter(x
.SelectMany(...).flat_map(...)중첩된 구조를 평탄화
.Any(...) / .All(...).any(...) / .all(...)논리 조건 검사
.Aggregate(...).fold(...)값을 하나로 축약

💡 실무 팁: itertools 크레이트

C#의 GroupBy, Distinct, Chunk 같은 더 강력한 기능이 필요하다면 itertools 크레이트를 사용하세요. 표준 라이브러리를 보완하는 다양한 연산자를 제공하여 LINQ와 거의 동등한(혹은 그 이상의) 표현력을 갖출 수 있습니다.

#![allow(unused)]
fn main() {
use itertools::Itertools;

// [중복 제거 예시]
let unique_items = items.into_iter().unique().collect_vec();
}