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

17-3. 코드 정제: '대입 피라미드' 허물기 🟡

학습 목표:

  • Rust의 식(Expression) 기반 문법과 클로저를 활용하여, 깊게 중첩된 if/else 대입문을 깔끔하고 선형적인 코드로 바꾸는 기법을 배웁니다.
  • '죽음의 피라미드'를 파괴하고 가독성 높은 선언적 코드를 설계하는 법을 익힙니다.
  • 즉시 실행 클로저와 ? 연산자의 조합으로 복잡한 조건 검증을 평탄화합니다.

1. 식(Expression) 기반 대입: "선언과 동시에 확정하기"

C++에서는 여러 조건에 따라 변수 값을 정하기 위해 if 문 내부에서 외부 변수를 수정(Mutate)해야 하는 경우가 많습니다. 하지만 Rust는 if 블록 자체가 값을 반환하는 '식'이므로, 단 한 번의 선언으로 모든 값을 확정할 수 있습니다.

#![allow(unused)]
fn main() {
// [C++ 스타일: 가변 변수와 다중 대입]
let mut code = 0;
let mut action = "";
if is_critical {
    code = 500; action = "STOP";
} else {
    code = 200; action = "OK";
}

// [Rust 스타일: 식을 이용한 원자적 대입]
let (code, action) = if is_critical {
    (500, "STOP")
} else {
    (200, "OK")
}; // 모든 변수가 불변(immutable)으로 깔끔하게 선언됨
}

2. 즉시 실행 클로저와 ? 연산자: "중첩 파괴하기"

데이터의 존재 여부를 층층이 확인하는 '검증 피라미드'는 클로저와 ? 연산자를 조합하여 완전히 평탄화할 수 있습니다.

#![allow(unused)]
fn main() {
// [피라미드 구조: 가독성 저하]
if let Some(a) = get_a() {
    if let Some(b) = a.get_b() {
        if let Some(c) = b.get_c() {
            return c;
        }
    }
}
"N/A"

// [평탄화된 흐름: 즉시 실행 클로저 활용]
let result = (|| {
    let a = get_a()?;
    let b = a.get_b()?;
    let c = b.get_c()?;
    Some(c)
})().unwrap_or("N/A");
}

3. 반복자 체인을 통한 루프 정제

수동으로 루프를 돌며 컬렉션에 데이터를 채우는 코드를 반복자 어댑터로 대체하면, 소유권 관련 버그를 방지하고 핵심 로직의 의도를 명확히 드러낼 수 있습니다.

전통적 루프 패턴Rust 반복자 대응핵심 효과
for + if { push }.filter().collect()조건에 맞는 요소만 깔끔하게 추출
for { transform + push }.map().collect()데이터 형식의 일괄 변환
for { if + break }.find() / .find_map()첫 번째 일치 항목 검색 및 안전한 변환
#![allow(unused)]
fn main() {
// [실전 예시] 실패한 테스트만 골라 이름 리스트 만들기
let failure_names: Vec<_> = test_results.iter()
    .filter(|t| !t.is_pass)      // 1. 탈락자 필터링
    .map(|t| t.name.clone())     // 2. 이름만 추출
    .collect();                  // 3. 최종 수집 (Allocation 최소화)
}

💡 실무 설계 팁

  • 변수를 미리 선언하고 나중에 채우지 마세요. 대신 식(Expression)을 통해 선언과 동시에 값을 확정하세요.
  • 깊은 중첩은 클로저로 감싸세요. ? 연산자가 복잡한 중첩을 단 몇 줄의 직관적인 체인으로 바꿔줄 것입니다.
  • 반복자(Iterator)는 단순한 루프가 아닙니다. 데이터를 흐르게 하고 정제하는 '파이프라인'입니다.

📌 요약

  • Rust의 모든 제어문은 값을 반환하는 **식(Expression)**으로 활용할 수 있습니다.
  • ? 연산자OptionResult의 중첩을 허무는 데 탁월한 도구입니다.
  • 명령형(Imperative) 루프를 선언적(Declarative) 반복자 체인으로 바꾸면 코드가 훨씬 견고해집니다.