IT’s Portfolio

[Rust] Start Rust (Day 22) - Functional Language Features: Iterators and Closures λ³Έλ¬Έ

Development Study/Rust

[Rust] Start Rust (Day 22) - Functional Language Features: Iterators and Closures

f1r3_r41n 2023. 11. 20. 14:58
728x90
λ°˜μ‘ν˜•

πŸ¦€ Rust Day 22

🏳️ Functional Language Features: Iterators and Closures

  • Closures : λ³€μˆ˜μ— μ €μž₯ν•  수 μžˆλŠ” ν•¨μˆ˜ ν˜•μ‹μ˜ ꡬ쑰
  • Iterators : 일련의 μ›μ†Œλ“€μ„ μ²˜λ¦¬ν•˜λŠ” 방법

1️⃣ ν΄λ‘œμ €: μ£Όλ³€ ν™˜κ²½μ„ μΊ‘μ²˜ν•˜λŠ” 읡λͺ… ν•¨μˆ˜

  • λ³€μˆ˜μ— μ €μž₯ν•˜κ±°λ‚˜ λ‹€λ₯Έ ν•¨μˆ˜μ— 인수둜 μ „λ‹¬ν•˜λŠ” 읡λͺ… ν•¨μˆ˜(anonymous functions)
  • 일반 ν•¨μˆ˜μ™€ 달리 ν΄λ‘œμ €λŠ” μžμ‹ μ΄ μ •μ˜λœ λ²”μœ„ λ‚΄μ˜ 값듀을 '캑처(capture)'함

πŸ€” ν΄λ‘œμ €λ₯Ό μ΄μš©ν•œ λ™μž‘μ˜ 좔상화

fn simulated_expensive_calculation(intensity: u32) -> u32 {
    println!("μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” 계산을 μˆ˜ν–‰ 쀑...");
    thread::sleep(Duration::from_secs(2));
    intensity
}
  • 싀행에 2μ΄ˆκ°€ κ±Έλ¦¬λŠ” κ°€μƒμ˜ 계산을 μˆ˜ν–‰ν•˜λŠ” simulated_expensive_calculation ν•¨μˆ˜
fn main() {
    let simulated_user_specified_value = 10;
    let simulated_random_number = 7;

    generate_workout(
        simulated_user_specified_value,
        simulated_random_number
    );
}
  • μ‚¬μš©μžμ˜ μž…λ ₯κ³Ό μž„μ˜μ˜ 숫자λ₯Ό ν•˜λ“œμ½”λ”©ν•œ 값을 μ΄μš©ν•˜λŠ” main ν•¨μˆ˜
fn generate_workout(intensity: u32, random_number: u32) {
    if intensity < 25 {
        println!(
            "μ˜€λŠ˜μ€ {}번의 νŒ”κ΅½ν˜€νŽ΄κΈ°λ₯Ό ν•˜μ„Έμš”!",
            simulated_expensive_calculation(intensity)
        );
        println!(
            "λ‹€μŒμ—λŠ” {}번의 μœ—λͺΈ μΌμœΌν‚€κΈ°λ₯Ό ν•˜μ„Έμš”!",
            simulated_expensive_calculation(intensity)
        );
    } else {
        if random_number == 3 {
            println!("μ˜€λŠ˜μ€ μˆ˜λΆ„μ„ μΆ©λΆ„νžˆ μ„­μ·¨ν•˜λ©° μ‰¬μ„Έμš”!");
        } else {
            println!(
                "μ˜€λŠ˜μ€ {}λΆ„κ°„ 달리기λ₯Ό ν•˜μ„Έμš”!",
                simulated_expensive_calculation(intensity)
            );
        }
    }
}
  • μž…λ ₯값에 따라 simulated_expensive_calculation ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄μ„œ μš΄λ™ κ³„νšμ„ μƒμ„±ν•˜λŠ” 둜직
  • simulated_expensive_calculation ν•¨μˆ˜λ₯Ό 단 ν•œ 번만 ν˜ΈμΆœν•˜λ„λ‘ λ¦¬νŒ©ν† λ§ ν•„μš”

(1) ν•¨μˆ˜λ₯Ό μœ„ν•œ λ¦¬νŒ©ν† λ§

fn generate_workout(intensity: u32, random_number: u32) {
    let expensive_result = simulated_expensive_calculation(intensity);

    if intensity < 25 {
        println!(
            "μ˜€λŠ˜μ€ {}번의 νŒ”κ΅½ν˜€νŽ΄κΈ°λ₯Ό ν•˜μ„Έμš”!",
            expensive_result
        );
        println!(
            "λ‹€μŒμ—λŠ” {}번의 μœ—λͺΈ μΌμœΌν‚€κΈ°λ₯Ό ν•˜μ„Έμš”!",
            expensive_result
        );
    } else {
        if random_number == 3 {
            println!("μ˜€λŠ˜μ€ μˆ˜λΆ„μ„ μΆ©λΆ„νžˆ μ„­μ·¨ν•˜λ©° μ‰¬μ„Έμš”!");
        } else {
            println!(
                "μ˜€λŠ˜μ€ {}λΆ„κ°„ 달리기λ₯Ό ν•˜μ„Έμš”!",
                expensive_result
            );
        }
    }
}
  • simulated_expensive_calculation ν•¨μˆ˜ ν˜ΈμΆœμ„ ν•œ 번만 μˆ˜ν–‰ν•˜κ³  κ·Έ κ²°κ³Όλ₯Ό expensive_result λ³€μˆ˜μ— μ €μž₯

(2) μ½”λ“œλ₯Ό μ €μž₯ν•˜λŠ” ν΄λ‘œμ €λ₯Ό μ΄μš©ν•œ λ¦¬νŒ©ν† λ§

fn generate_workout(intensity: u32, random_number: u32) {
    let expensive_closure = |num| {
        println!("μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” 계산을 μˆ˜ν–‰ 쀑...");
        thread::sleep(Duration::from_secs(2));
        num
    };

    if intensity < 25 {
        println!(
            "μ˜€λŠ˜μ€ {}번의 νŒ”κ΅½ν˜€νŽ΄κΈ°λ₯Ό ν•˜μ„Έμš”!",
            expensive_closure(intensity)
        );
        println!(
            "λ‹€μŒμ—λŠ” {}번의 μœ—λͺΈ μΌμœΌν‚€κΈ°λ₯Ό ν•˜μ„Έμš”!",
            expensive_closure(intensity)
        );
    } else {
        if random_number == 3 {
            println!("μ˜€λŠ˜μ€ μˆ˜λΆ„μ„ μΆ©λΆ„νžˆ μ„­μ·¨ν•˜λ©° μ‰¬μ„Έμš”!");
        } else {
            println!(
                "μ˜€λŠ˜μ€ {}λΆ„κ°„ 달리기λ₯Ό ν•˜μ„Έμš”!",
                expensive_closure(intensity)
            );
        }
    }
}
  • ν΄λ‘œμ €λ₯Ό μ„ μ–Έν•˜κ³  expensive_closure λ³€μˆ˜μ— μ €μž₯
    • ν΄λ‘œμ € 선언은 λ³€μˆ˜μ— 값을 ν• λ‹Ήν•˜λŠ” = λ‹€μŒλΆ€ν„° μ‹œμž‘ν•¨
    • ν΄λ‘œμ € μ„ μ–Έ μ‹œ νŒŒμ΄ν”„ 문자의 쌍이 ν•„μš”ν•¨
      • νŒŒμ΄ν”„ 문자 μ‚¬μ΄μ—λŠ” ν΄λ‘œμ €μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 지정할 수 있음
    • ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” μ½”λ“œλ₯Ό ν•œ 곳에 μ •μ˜ν•˜κ³  κ·Έ μ½”λ“œλ₯Ό μ €μž₯ν•΄μ„œ ν•„μš”ν•  λ•Œ λ‚˜μ€‘μ— ν˜ΈμΆœν•˜κΈ° μœ„ν•¨
  • expensive_closure ν΄λ‘œμ €λ₯Ό ν˜ΈμΆœν•˜λŠ” generate_workout ν•¨μˆ˜

πŸ€” ν΄λ‘œμ €μ˜ νƒ€μž… μΆ”λ‘ κ³Ό μ• λ…Έν…Œμ΄μ…˜

let expensive_result = |num: u32| -> u32 {
    println!("μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” 계산을 μˆ˜ν–‰ 쀑...");
    thread::sleep(Duration::from_secs(2));
    num
}
  • ν΄λ‘œμ € μ„ μ–Έ μ‹œ ν•¨μˆ˜μ²˜λŸΌ λ§€κ°œλ³€μˆ˜μ™€ λ¦¬ν„΄κ°’μ˜ νƒ€μž…μ„ 지정할 ν•„μš”κ°€ μ—†μŒ
    • ν΄λ‘œμ €λŠ” λ³€μˆ˜μ— μ €μž₯되고 이름도 μ—†μœΌλ©° 라이브러리의 μ‚¬μš©μžμ—κ²Œ λ…ΈμΆœλ˜μ§€λ„ μ•ŠμŒ
  • λ³€μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 가독성을 λ†’μ΄λŠ” 일이 μž₯ν™©ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 것보닀 더 μ€‘μš”ν•  λ•Œ ν΄λ‘œμ €μ—λ„ νƒ€μž… μ• λ…Έν…Œμ΄μ…˜μ„ μΆ”κ°€ν•  수 있음
fn add_one_1(x: u32) -> u32 { x+1 } // ν•¨μˆ˜μ˜ μ •μ˜
let add_one_2 = |x: u32| -> u32 { x+1 }; // νƒ€μž… μ• λ…Έν…Œμ΄μ…˜μ„ μ μš©ν•œ ν΄λ‘œμ € μ„ μ–Έ
let add_one_3 = |x| { x+1 }; // ν΄λ‘œμ € μ„ μ–Έμ—μ„œ νƒ€μž… μ• λ…Έν…Œμ΄μ…˜ 제거
let add_one_4 = |x| x+1; // ν•˜λ‚˜μ˜ ν‘œν˜„μ‹μœΌλ‘œλ§Œ κ΅¬ν˜„λœ ν΄λ‘œμ € μ„ μ–Έμ΄λ―€λ‘œ κ΄„ν˜ΈκΉŒμ§€ μ œκ±°ν•¨
let example_closure = |x| x
let s = example_closure(String::from("hello"));
let n = example_closure(5);
  • 처음 String νƒ€μž…μ„ 인수둜 λ„£μ–΄ ν˜ΈμΆœν•œ ν΄λ‘œμ €λŠ” λ‹€λ₯Έ νƒ€μž…μ„ 인수둜 λ„£μ–΄ ν˜ΈμΆœν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•¨
    • 처음 νƒ€μž… 정보가 ν•΄λ‹Ή ν΄λ‘œμ €μ— 기둝되기 λ•Œλ¬Έ

πŸ€” μ œλ„€λ¦­ λ§€κ°œλ³€μˆ˜μ™€ Fn 트레이트λ₯Ό μ΄μš©ν•΄ ν΄λ‘œμ € μ €μž₯ν•˜κΈ°

  • λ©”λͺ¨μ΄μ œμ΄μ…˜(memoization) or 지연 평가(lazy evaluation) 기법
    • ν΄λ‘œμ €μ™€ ν΄λ‘œμ €μ˜ μ‹€ν–‰ κ²°κ³Όλ₯Ό μ €μž₯ν•  ꡬ쑰체 μ„ μ–Έ
    • κ΅¬μ‘°μ²΄λŠ” 결괏값이 ν•„μš”ν•  λ•Œλ§Œ ν΄λ‘œμ €λ₯Ό μ‹€ν–‰ν•œ ν›„ κ·Έ 결괏값을 캐싱함
    • λ‚˜λ¨Έμ§€ μ½”λ“œμ—μ„œλŠ” κ·Έ 결괏값을 λ”°λ‘œ μ €μž₯ν•˜κ³  μž¬μ‚¬μš©ν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ μ•Šμ•„λ„ 됨
struct Cacher<T> where T: Fn(u32) -> u32 {
    calculation: T,
    value: Option<u32>,
}
  • ν΄λ‘œμ €μ™€ 리턴값을 calculationκ³Ό value ν•„λ“œμ— μ €μž₯ν•˜λŠ” Cacher ꡬ쑰체
    • ꡬ쑰체 μ„ μ–Έ μ‹œ 각 ν•„λ“œμ˜ νƒ€μž…μ„ μ•Œμ•„μ•Ό ν•˜λ―€λ‘œ ν΄λ‘œμ €μ˜ νƒ€μž…μ„ λͺ…μ‹œν•΄μ•Ό 함
    • ν΄λ‘œμ € μΈμŠ€ν„΄μŠ€λŠ” 각자 μœ μΌν•œ 읡λͺ… νƒ€μž…μ„ 가지고 있음
      • 두 개의 ν΄λ‘œμ €κ°€ 같은 μ‹œκ·Έλ‹ˆμ²˜λ₯Ό 갖더라도 μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ 인식함
    • μ œλ„€λ¦­ T νƒ€μž…μ˜ calculation ν•„λ“œ
      • T νƒ€μž…μ€ Fn 트레이트 경계λ₯Ό 지정해 이 νƒ€μž…μ΄ ν΄λ‘œμ €μ—¬μ•Ό ν•˜λ‚˜λŠ” 사싀을 λͺ…μ‹œν•¨
    • Option νƒ€μž…μ˜ value ν•„λ“œ
      • ν΄λ‘œμ €λ₯Ό μ‹€ν–‰ν•˜κΈ° μ „μ—λŠ” None κ°’μž„
      • ꡬ쑰체λ₯Ό μ΄μš©ν•˜λŠ” μ½”λ“œκ°€ ν΄λ‘œμ €μ˜ κ²°κ³Όλ₯Ό μš”μ²­ν•˜λ©΄ κ·Έ μ‹œμ μ— ν΄λ‘œμ €λ₯Ό ν˜ΈμΆœν•œ λ’€ 결괏값을 Some 열것값에 μ €μž₯ν•΄ ν•„λ“œμ— μ €μž₯
impl<T> Cacher<T> where T: Fn(u32) -> u32 {
    fn new(calculation: T) -> Cacher<T> {
        Cacher {
            calculation,
            value: None,
        }
    }
    fn value(&mut self, arg: u32) -> u32 {
        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            }
        }
    }
}
  • Cacher ꡬ쑰체의 캐싱 둜직
    • λ‹€λ₯Έ μ½”λ“œκ°€ ꡬ쑰체의 value ν•„λ“œκ°’μ„ μž„μ˜λ‘œ λ³€κ²½ν•˜κΈ°λ₯Ό μ›μΉ˜ μ•ŠκΈ° λ•Œλ¬Έμ— 이 ν•„λ“œλŠ” λΉ„κ³΅κ°œλ‘œ 선언함
fn generate_workout(intensity: u32, random_number: u32) {
    let mut expensive_result = Cacher::new(
        |num| {
            println!("μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” 계산을 μˆ˜ν–‰ 쀑...");
            thread::sleep(Duration::from_secs(2));
            num
        }
    );

    if intensity < 25 {
        println!(
            "μ˜€λŠ˜μ€ {}번의 νŒ”κ΅½ν˜€νŽ΄κΈ°λ₯Ό ν•˜μ„Έμš”!",
            expensive_result.value(intensity)
        );
        println!(
            "λ‹€μŒμ—λŠ” {}번의 μœ—λͺΈ μΌμœΌν‚€κΈ°λ₯Ό ν•˜μ„Έμš”!",
            expensive_result.value(intensity)
        );
    } else {
        if random_number == 3 {
            println!("μ˜€λŠ˜μ€ μˆ˜λΆ„μ„ μΆ©λΆ„νžˆ μ„­μ·¨ν•˜λ©° μ‰¬μ„Έμš”!");
        } else {
            println!(
                "μ˜€λŠ˜μ€ {}λΆ„κ°„ 달리기λ₯Ό ν•˜μ„Έμš”!",
                expensive_result.value(intensity)
            );
        }
    }
}
  • generate_workout ν•¨μˆ˜μ—μ„œ Cacher ꡬ쑰체λ₯Ό μ΄μš©ν•΄ 캐싱 둜직 좔상화

πŸ€” Cacher κ΅¬ν˜„μ˜ ν•œκ³„

  • κ°’ 캐싱 방법은 λ‹€λ₯Έ μ½”λ“œμ—μ„œ λ‹€λ₯Έ ν΄λ‘œμ €λ₯Ό ν˜ΈμΆœν•  λ•Œ μœ μš©ν•¨
  • Cacher ꡬ쑰체의 문제
    • Cacher μΈμŠ€ν„΄μŠ€λŠ” 항상 처음으둜 호좜된 value λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜ arg에 μ „λ‹¬λœ κ°’κ³Ό κ°™λ‹€λŠ” 점
      • Cacherκ°€ ν•˜λ‚˜μ˜ κ°’ λŒ€μ‹  ν•΄μ‹œ 맡을 μ €μž₯ν•˜λ„λ‘ μˆ˜μ •ν•΄μ•Ό 함
    • u32 νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜ ν•˜λ‚˜μ™€ u32 νƒ€μž…μ˜ 리턴값을 κ°€μ§€λŠ” ν΄λ‘œμ €λ§Œ μ €μž₯ν•  수 μžˆλ‹€λŠ” 점
      • λ¬Έμžμ—΄ 슬라이슀λ₯Ό 인수둜 전달받아 usize 값을 λ¦¬ν„΄ν•˜λŠ” ν΄λ‘œμ €μ˜ μ‹€ν–‰ κ²°κ³ΌλŠ” μΊμ‹œν•  수 μ—†μŒ
      • μ œλ„€λ¦­ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄μ•Ό 함
#[test]
fn call_with_different_value() {
    let mut c = Cacher::new(|a| a);
    let v1 = c.value(1);
    let v2 = c.value(2);
    assert_eq!(v2, 2);
}
  • 처음 c.value λ©”μ„œλ“œμ— 1을 전달해 ν˜ΈμΆœν•˜λ©΄ Cacher μΈμŠ€ν„΄μŠ€κ°€ self.value ν•„λ“œμ— Some(1) 값을 μ €μž₯함
  • 이후 value λ©”μ„œλ“œμ— μ–΄λ–€ 값을 μ „λ‹¬ν•˜λ“  무쑰건 1을 리턴함
  • ν•΄λ‹Ή ν…ŒμŠ€νŠΈλŠ” μ‹€νŒ¨ν•¨

πŸ€” ν΄λ‘œμ €λ₯Ό μ΄μš©ν•΄ μ£Όλ³€ ν™˜κ²½ μΊ‘μ²˜ν•˜κΈ°

fn main() {
    let x = 4;
    let equal_to_x = |z| z == x;
    let y = 4;
    assert!(equal_to_x(y));
}
  • μžμ‹  주변에 μ„ μ–Έλœ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” ν΄λ‘œμ €
  • λ³€μˆ˜ xλŠ” equal_to_x ν΄λ‘œμ €μ˜ λ§€κ°œλ³€μˆ˜κ°€ μ•„λ‹Œλ°λ„ μžμ‹ μ΄ μ„ μ–Έλœ 것과 같은 λ²”μœ„μ— μ„ μ–Έλœ λ³€μˆ˜ x에 μ ‘κ·Όν•  수 있음
fn main() {
    let x = 4;
    fn equal_to_x(z: i32) -> bool { z == x };
    let y = 4;
    assert!(equal_to_x(y));
}
  • ν΄λ‘œμ €λ₯Ό ν•¨μˆ˜λ‘œ λ°”κΎΌ μ½”λ“œ
  • μ»΄νŒŒμΌλ˜μ§€ μ•ŠμŒ

  • ν΄λ‘œμ €λŠ” μžμ‹ μ˜ μ£Όλ³€μ—μ„œ 값을 μΊ‘μ²˜ν•  λ•Œ ν΄λ‘œμ €μ˜ λ³Έλ¬Έμ—μ„œ μ‚¬μš©ν•  값을 λ©”λͺ¨λ¦¬μ— μ €μž₯함
    • λ©”λͺ¨λ¦¬λ₯Ό μ΄λ ‡κ²Œ μ‚¬μš©ν•˜λ©΄ μ£Όλ³€μ˜ 값을 μΊ‘μ²˜ν•  ν•„μš”κ°€ μ—†λŠ” μ½”λ“œλ₯Ό μ‹€ν–‰ν•  λ•Œλ³΄λ‹€λŠ” 더 λ§Žμ€ μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•¨
  • ν•¨μˆ˜λŠ” μ£Όλ³€μ˜ ν™˜κ²½μ„ μΊ‘μ²˜ν•˜μ§€ μ•ŠμŒ
    • μ£Όλ³€μ˜ 값이 ν•„μš”ν•˜μ§€ μ•Šμ„ λ•ŒλŠ” μ˜€λ²„ν—€λ“œλ₯Ό 쀄이기 μœ„ν•΄ ν•¨μˆ˜λ₯Ό μ‚¬μš©
  • ν΄λ‘œμ €λŠ” μžμ‹ μ˜ 주변에 μ„ μ–Έλœ 값을 ν•¨μˆ˜κ°€ λ§€κ°œλ³€μˆ˜λ₯Ό μ €μž₯ν•˜λŠ” μ„Έ 가지 방법과 λ™μΌν•˜κ²Œ μΊ‘μ²˜ν•¨
    • μ†Œμœ κΆŒμ„ κ°€μ Έμ˜€λŠ” 방법
      • FnOnce νŠΈλ ˆμ΄νŠΈλŠ” 같은 λ²”μœ„μ— μ„ μ–Έλœ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  수 있음
        • 이 λ²”μœ„λ₯Ό ν΄λ‘œμ €μ˜ 'ν™˜κ²½(environment)'이라고 함
        • ν΄λ‘œμ €λŠ” 캑처된 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ €λ©΄ λ°˜λ“œμ‹œ 이 λ³€μˆ˜λ“€μ˜ μ†Œμœ κΆŒμ„ κ°€μ Έμ•Ό ν•˜λ©°, ν΄λ‘œμ €λ₯Ό μ„ μ–Έν•˜λŠ” μ‹œμ μ— 이 λ³€μˆ˜λ₯Ό ν΄λ‘œμ € μ•ˆμœΌλ‘œ 이동함
        • 트레이트의 μ΄λ¦„μ—μ„œ Onceκ°€ μ˜λ―Έν•˜λŠ” 것은 ν΄λ‘œμ €κ°€ 같은 값에 λŒ€ν•œ μ†Œμœ κΆŒμ„ 였직 ν•œ 번만 κ°€μ§„λ‹€λŠ” λœ»μž„
    • 값을 κ°€λ³€μœΌλ‘œ λŒ€μ—¬ν•˜λŠ” 방법
      • FnMut νŠΈλ ˆμ΄νŠΈλŠ” 값을 κ°€λ³€μœΌλ‘œ λŒ€μ—¬ν•˜λ―€λ‘œ ν™˜κ²½μ—μ„œ κ°€μ Έμ˜¨ 값을 λ³€κ²½ν•  수 있음
    • 값을 λΆˆλ³€μœΌλ‘œ λŒ€μ—¬ν•˜λŠ” 방법
      • Fn νŠΈλ ˆμ΄νŠΈλŠ” ν™˜κ²½μ—μ„œ 값을 λΆˆλ³€μœΌλ‘œ λŒ€μ—¬ν•¨
  • λͺ¨λ“  ν΄λ‘œμ €λŠ” μ΅œμ†Œν•œ ν•œ λ²ˆμ€ 호좜될 수 μžˆμœΌλ―€λ‘œ FnOnce 트레이트λ₯Ό κ΅¬ν˜„ν•¨
  • ν™˜κ²½μ—μ„œ κ°€μ Έμ˜¨ 값을 μ΄λ™ν•˜μ§€ μ•ŠλŠ” ν΄λ‘œμ €λŠ” FnMut νŠΈλ ˆμ΄νŠΈλ„ κ΅¬ν˜„ν•˜κ²Œ 되며 캑처된 λ³€μˆ˜λ₯Ό λ³€κ²½ν•˜μ§€ μ•ŠλŠ” ν΄λ‘œμ €λŠ” Fn 트레이트λ₯Ό κ΅¬ν˜„ν•¨
  • ν΄λ‘œμ €κ°€ ν™˜κ²½μ—μ„œ κ°€μ Έμ˜¨ 값에 λŒ€ν•œ μ†Œμœ κΆŒμ„ κ°–κ²Œ ν•˜λ €λ©΄ λ§€κ°œλ³€μˆ˜ λͺ©λ‘ μ•žμ— move ν‚€μ›Œλ“œλ₯Ό 지정함
    • 이 기법은 ν΄λ‘œμ €λ₯Ό μƒˆλ‘œμš΄ μŠ€λ ˆλ“œμ— μ „λ‹¬ν•΄μ„œ κ·Έ μŠ€λ ˆλ“œμ— 데이터λ₯Ό μ΄λ™ν•΄μ„œ μ†Œμœ ν•˜κ²Œ ν•  λ•Œ μœ μš©ν•¨
fn main() {
    let x = vec![1, 2, 3];
    let equal_to_x = move |z| z == x;
    println!("λ³€μˆ˜ xλ₯Ό μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€: {:?}", x);
    let y = vec![1, 2, 3];
    assert!(equal_to_x(y));
}
  • 이 μ½”λ“œλŠ” μ—λŸ¬κ°€ λ°œμƒν•¨
  • ν΄λ‘œμ € μ„ μ–Έ μ‹œ λ³€μˆ˜ xλŠ” move ν‚€μ›Œλ“œλ‘œ 인해 ν΄λ‘œμ € μ•ˆμœΌλ‘œ 이동함
  • ν΄λ‘œμ €κ°€ x의 μ†Œμœ κΆŒμ„ κ°€μ§€λ―€λ‘œ main ν•¨μˆ˜λŠ” println! 맀크둜λ₯Ό ν˜ΈμΆœν•  λ•Œ x에 μ ‘κ·Όν•  수 μ—†μŒ

2️⃣ 반볡자λ₯Ό μ΄μš©ν•΄ 일련의 μ•„μ΄ν…œ μ²˜λ¦¬ν•˜κΈ°

  • λ°˜λ³΅μžλŠ” μ•„μ΄ν…œμ„ μˆœνšŒν•˜λ©΄μ„œ λ§ˆμ§€λ§‰ μ•„μ΄ν…œμ— λ„λ‹¬ν•˜λŠ” λ•Œλ₯Ό νŒλ‹¨ν•¨
  • 지연(lazy) νŠΉμ„±μ΄ 있음
    • 반볡자λ₯Ό λ³€μˆ˜μ— μ €μž₯ν•  λ•ŒλŠ” μ•„μ΄ν…œμ„ μˆœνšŒν•˜λŠ” μž‘μ—…μ΄ μ§„ν–‰λ˜μ§€ μ•ŠμŒ
    • for 루프가 λ³€μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ 반볡자λ₯Ό μ΄μš©ν•΄ 각 μ•„μ΄ν…œμ„ μˆœνšŒν•˜κ³  κ°œλ³„ 값을 좜λ ₯함
  • λŸ¬μŠ€νŠΈμ—μ„œλŠ” 반볡자둜 λ°˜λ³΅λ˜λŠ” λ‘œμ§μ„ 쀄일 수 있으며 μœ μ—°μ„±κΉŒμ§€ κ°€μ§ˆ 수 있음

πŸ€” Iterator νŠΈλ ˆμ΄νŠΈμ™€ next λ©”μ„œλ“œ

  • λͺ¨λ“  λ°˜λ³΅μžλ“€μ€ ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— μ •μ˜λœ Iterator 트레이트λ₯Ό κ΅¬ν˜„ν•¨
pub trait Iterator {
    type Item,
    fn next(&mut self) -> Option<Self::Item>;
}
  • Iterator 트레이트λ₯Ό κ΅¬ν˜„ν•˜λ €λ©΄ Item νƒ€μž…λ„ μ •μ˜ν•΄μ•Ό ν•˜λ©°, 이 Item νƒ€μž…μ€ next λ©”μ„œλ“œμ˜ 리턴 νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•¨
#[test]
fn iterator_demonstration() {
    let v1 = vec![1, 2, 3];
    let mut v1_iter = v1.iter();
    assert_eq!(v1_iter.next(), Some(&1));
    assert_eq!(v1_iter.next(), Some(&2));
    assert_eq!(v1_iter.next(), Some(&3));
    assert_eq!(v1_iter.next(), None);
}
  • 반볡자의 next λ©”μ„œλ“œ 호좜
  • v1_iter λ³€μˆ˜λ₯Ό κ°€λ³€μœΌλ‘œ 선언함
    • next λ©”μ„œλ“œλ‘œ ν˜ΈμΆœν•˜λ©΄ 이미 λ¦¬ν„΄ν•œ 값을 μΆ”μ ν•˜λ €κ³  반볡자 λ‚΄λΆ€μ˜ μƒνƒœκ°€ 변경됨
    • 반볡자λ₯Ό 'μ†ŒλΉ„(consume)' 함
      • next λ©”μ„œλ“œ 호좜 λ•Œλ§ˆλ‹€ 반볡자의 μ•„μ΄ν…œμ„ 리턴함
  • v1_iter λ³€μˆ˜λ₯Ό for 루프 μ•ˆμ—μ„œ μ‚¬μš©ν•˜λ©΄ 루프가 v1_iter에 λŒ€ν•œ μ†Œμœ κΆŒμ„ 가지고 κ°€λ³€ λ³€μˆ˜λ‘œ λ§Œλ“€κΈ° λ•Œλ¬Έμ— 반볡자 λ³€μˆ˜λ₯Ό κ°€λ³€ λ³€μˆ˜λ‘œ μ„ μ–Έν•  ν•„μš”κ°€ μ—†μŒ
  • next λ©”μ„œλ“œλ‘œ μ–»μ–΄μ˜¨ 값은 벑터 μ•ˆμ— μ €μž₯된 값에 λŒ€ν•œ λΆˆλ³€ μ°Έμ‘°μž„
    • iter λ©”μ„œλ“œλŠ” λΆˆλ³€ μ°Έμ‘°λ₯Ό μˆœνšŒν•˜λŠ” 반볡자λ₯Ό 생성함
  • v1에 λŒ€ν•œ μ†Œμœ κΆŒμ„ 가지고 μ†Œμœ ν•œ 값을 λ¦¬ν„΄ν•˜λŠ” 반볡자 생성 μ‹œ iter λŒ€μ‹  into_iter λ©”μ„œλ“œ 호좜
    • κ°€λ³€ μ°Έμ‘° 순회 μ‹œ iter λŒ€μ‹  iter_mut λ©”μ„œλ“œ 호좜

πŸ€” 반볡자λ₯Ό μ†ŒλΉ„ν•˜λŠ” λ©”μ„œλ“œ

  • 일뢀 λ©”μ„œλ“œλŠ” next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ―€λ‘œ Iterator 트레이트λ₯Ό κ΅¬ν˜„ν•˜λ €λ©΄ next λ©”μ„œλ“œλ₯Ό λ°˜λ“œμ‹œ κ΅¬ν˜„ν•΄μ•Ό 함
  • μ†ŒλΉ„ μ–΄λŒ‘ν„°(consuming adaptors)
    • λ‚΄λΆ€μ μœΌλ‘œ 반볡자λ₯Ό μ†ŒλΉ„ν•˜λŠ” next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œ
#[test]
fn iterator_sum() {
    let v1 = vec![1, 2, 3];
    let v1_iter = v1.iter();
    let total: i32 = v1_iter.sum();
    assert_eq!(total, 6);
}
  • 반볡자 λ‚΄ μ•„μ΄ν…œ 총합을 μ–»κΈ° μœ„ν•΄ sum λ©”μ„œλ“œ 호좜
  • sum λ©”μ„œλ“œλŠ” λ°˜λ³΅μžμ— λŒ€ν•œ μ†Œμœ κΆŒμ„ κ°–κΈ° λ•Œλ¬Έμ— 이 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ ν›„μ—λŠ” v1_iter λ³€μˆ˜λ₯Ό 더 이상 μ‚¬μš©ν•  수 μ—†μŒ

πŸ€” λ‹€λ₯Έ 반볡자λ₯Ό μƒμ„±ν•˜λŠ” λ©”μ„œλ“œ

  • 반볡자 μ–΄λŒ‘ν„°(iterator adaptors)
    • 반볡자λ₯Ό λ‹€λ₯Έ μ’…λ₯˜μ˜ 반볡자둜 변경함
    • λͺ¨λ“  λ°˜λ³΅μžλŠ” 지연 νŠΉμ„±μ΄ μžˆμœΌλ―€λ‘œ 반볡자 μ–΄λŒ‘ν„°λ₯Ό ν˜ΈμΆœν•œ ν›„μ˜ κ²°κ³Όλ₯Ό μ–»μœΌλ €λ©΄ μ†ŒλΉ„ μ–΄λŒ‘ν„° λ©”μ„œλ“œ 쀑 ν•˜λ‚˜λ₯Ό ν˜ΈμΆœν•΄μ•Ό 함
fn main() {
    let v1: Vec<i32> = vec![1, 2, 3];
    v1.iter().map(|x| x+1);
}
  • μƒˆλ‘œμš΄ 반볡자λ₯Ό μƒμ„±ν•˜λŠ” 반볡자 μ–΄λŒ‘ν„° map λ©”μ„œλ“œ
  • ν•΄λ‹Ή μ½”λ“œλŠ” μ•„λ¬΄λŸ° μž‘μ—…λ„ μˆ˜ν–‰ν•˜μ§€ μ•ŠμŒ
    • map λ©”μ„œλ“œμ— μ „λ‹¬ν•œ ν΄λ‘œμ €λŠ” μ ˆλŒ€ ν˜ΈμΆœλ˜μ§€ μ•ŠμŒ
fn main() {
    let v1: Vec<i32> = vec![1, 2, 3];
    let v2 = v1.iter().map(|x| x+1).collect::<Vec<_>>();
    assert_eq!(v2, vec![2, 3, 4]);
}
  • map λ©”μ„œλ“œλ‘œ μƒˆλ‘œμš΄ 반볡자 생성 ν›„ collect λ©”μ„œλ“œλ‘œ 벑터 생성
  • map λ©”μ„œλ“œλŠ” ν΄λ‘œμ €λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ μ‚¬μš©ν•˜λ―€λ‘œ 각 μ•„μ΄ν…œμ— μ μš©ν•  μ–΄λ–€ μž‘μ—…λ„ 전달 κ°€λŠ₯

πŸ€” ν™˜κ²½μ„ μΊ‘μ²˜ν•˜λŠ” ν΄λ‘œμ €μ˜ ν™œμš©

  • 반볡자의 filter λ©”μ„œλ“œλŠ” λ°˜λ³΅μžλ‘œλΆ€ν„° 각 μ•„μ΄ν…œμ„ 가져와 λΆˆλ¦¬μ–Έκ°’μ„ λ¦¬ν„΄ν•˜λŠ” ν΄λ‘œμ €μ— 전달함
  • ν΄λ‘œμ €κ°€ trueλ₯Ό λ¦¬ν„΄ν•˜λ©΄ κ·Έ 값은 filter λ©”μ„œλ“œκ°€ μƒμ„±ν•˜λŠ” λ°˜λ³΅μžμ— μΆ”κ°€λ˜κ³  falseλ₯Ό λ¦¬ν„΄ν•˜λ©΄ μΆ”κ°€λ˜μ§€ μ•ŠμŒ
#[derive(PartialEq, Debug)]

struct Shoe {
    size: u32,
    style: String,
}

fn shoe_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
    shoes.into_iter()
        .filter(|s| s.size == shoe_size)
        .collect()
}

#[test]
fn filters_by_size() {
    let shoes = vec![
        Shoe { size: 10, style: String::from("μŠ€λ‹ˆμ»€μ¦ˆ") },
        Shoe { size: 13, style: String::from("μƒŒλ‹¬") },
        Shoe { size: 10, style: String::from("λΆ€μΈ ") },
    ];
    let in_my_size = shoe_in_my_size(shoes, 10);
    assert_eq!(
        in_my_size,
        vec![
            Shoe { size: 10, style: String::from("μŠ€λ‹ˆμ»€μ¦ˆ") },
            Shoe { size: 10, style: String::from("λΆ€μΈ ") },
        ]
    );
}
  • shoe_size λ³€μˆ˜λ₯Ό μΊ‘μ²˜ν•œ ν΄λ‘œμ €λ₯Ό filter λ©”μ„œλ“œμ— 전달

πŸ€” Iterator 트레이트λ₯Ό μ΄μš©ν•΄ 직접 반볡자 κ΅¬ν˜„ν•˜κΈ°

  • 직접 μ„ μ–Έν•œ νƒ€μž…μ— Iterator 트레이트λ₯Ό κ΅¬ν˜„ν•΄μ„œ ν•„μš”ν•œ μž‘μ—… μˆ˜ν–‰ κ°€λŠ₯
    • next λ©”μ„œλ“œ κ΅¬ν˜„ μ‹œ Iterator νŠΈλ ˆμ΄νŠΈκ°€ 기본적으둜 κ΅¬ν˜„ν•΄ μ œκ³΅ν•˜λŠ” λ‹€λ₯Έ λ©”μ„œλ“œλ„ λͺ¨λ‘ μ‚¬μš© κ°€λŠ₯
struct Counter {
    count: u32,
}

impl Counter {
    fn new() -> Counter {
        Counter { count: 0 }
    }
}
  • Counter ꡬ쑰체λ₯Ό μ„ μ–Έν•˜κ³  count ν•„λ“œμ— 0을 μ΄ˆκΉƒκ°’μœΌλ‘œ λŒ€μž…ν•΄ μƒˆ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” new ν•¨μˆ˜
impl Iterator for Counter {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        self.count += 1;
        if self.count < 6 {
            Some(self.count)
        } else {
            None
        }
    }
}
  • Counter ꡬ쑰체에 Iterator 트레이트 κ΅¬ν˜„
  • λ°˜λ³΅μžκ°€ u32 값을 λ¦¬ν„΄ν•˜λ„λ‘ λ°˜λ³΅μžμ™€ μ—°κ΄€λœ νƒ€μž…μΈ Item νƒ€μž…μ€ u32둜 지정
  • 0으둜 μ΄ˆκΈ°ν™”ν–ˆλ˜ ν˜„μž¬ μƒνƒœμ— 1을 λ”ν•΄μ„œ λ°˜λ³΅μžκ°€ 1λΆ€ν„° λ¦¬ν„΄ν•˜λ„λ‘ 함
    • 만일, count 값이 6보닀 μž‘μœΌλ©΄ next λ©”μ„œλ“œλŠ” ν˜„μž¬ 값을 Some 값에 μ €μž₯ν•΄ λ¦¬ν„΄ν•˜κ³ , count 값이 6보닀 크면 None 값을 리턴함

πŸ€” Counter 반볡자의 next λ©”μ„œλ“œ μ‚¬μš©ν•˜κΈ°

#[test]
fn calling_next_directly() {
    let mut counter = Counter::new();
    assert_eq!(counter.next(), Some(1));
    assert_eq!(counter.next(), Some(2));
    assert_eq!(counter.next(), Some(3));
    assert_eq!(counter.next(), Some(4));
    assert_eq!(counter.next(), Some(5));
    assert_eq!(counter.next(), None);
}
  • next λ©”μ„œλ“œ κ΅¬ν˜„ ν…ŒμŠ€νŠΈ

πŸ€” Iterator 트레이트의 λ‹€λ₯Έ λ©”μ„œλ“œ ν™œμš©ν•˜κΈ°

#[test]
fn using_other_iterator_trait_methods() {
    let sum: u32 = Counter::new().zip(Counter::new().skip(1))
        .map(|(a, b)| a*b)
        .filter(|x| x%3==0)
        .sum();
    assert_eq!(18, sum);
}
  • Counter ꡬ쑰체의 μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±ν•œ 값을 λ‹€λ₯Έ Counter μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±ν•œ κ°’ 쀑 첫 번째 값을 μ œμ™Έν•œ λ‚˜λ¨Έμ§€μ™€ 짝지어 μ„œλ‘œλ₯Ό κ³±ν•œ ν›„, 3으둜 λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§€λŠ” κ°’λ§Œ 골라 결괏값을 λͺ¨λ‘ 더함
    • zip λ©”μ„œλ“œλŠ” λ„€ 개의 쌍만 생성
      • 두 반볡자 쀑 μ–΄λŠ ν•˜λ‚˜κ°€ None 값을 λ¦¬ν„΄ν•˜λ©΄ None을 λ¦¬ν„΄ν•˜λ―€λ‘œ λ‹€μ„― 번째 짝인 (5, None)은 μƒμ„±λ˜μ§€ μ•ŠμŒ
  • next λ©”μ„œλ“œ λ™μž‘μ„ κ΅¬ν˜„ν–ˆμœΌλ―€λ‘œ λ‚˜λ¨Έμ§€ λͺ¨λ“  λ©”μ„œλ“œλ„ ν˜ΈμΆœν•  수 μžˆμŒμ„ 확인 κ°€λŠ₯

3️⃣ μž…μΆœλ ₯ ν”„λ‘œμ νŠΈμ˜ κ°œμ„ 

πŸ€” 반볡자λ₯Ό μ΄μš©ν•΄ clone λ©”μ„œλ“œ 호좜 μ œκ±°ν•˜κΈ°

impl Config {
    pub fn new(args: &[String]) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("ν•„μš”ν•œ μΈμˆ˜κ°€ μ§€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.");
        }
        Ok(Config {
            query: args[1].clone(),
            filename: args[2].clone(),
            case_sensitive: env::var("CASE_INSENSITIVE").is_err()
        })
    }
}
  • Config::new ν•¨μˆ˜μ˜ λΉ„νš¨μœ¨μ μΈ clone λ©”μ„œλ“œ
    • new ν•¨μˆ˜κ°€ String 슬라이슀인 args λ³€μˆ˜λ₯Ό μ†Œμœ ν•˜μ§€ μ•Šμ•˜κΈ°μ— clone λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν–ˆμŒ
    • 이제 new ν•¨μˆ˜κ°€ 슬라이슀λ₯Ό λŒ€μ—¬ν•˜λŠ” λŒ€μ‹  인수둜 μ „λ‹¬λœ 반볡자의 μ†Œμœ κΆŒμ„ 갖도둝 μˆ˜μ •ν•˜λ©΄ 됨
      • Config::new ν•¨μˆ˜κ°€ 반볡자의 μ†Œμœ κΆŒμ„ ν™•λ³΄ν•˜κ³  값을 λŒ€μ—¬ν•˜λŠ” 인덱슀 μž‘μ—…μ„ μ œκ±°ν•˜λ©΄ clone λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄ μƒˆλ‘œμš΄ λ©”λͺ¨λ¦¬ 할당을 μˆ˜ν–‰ν•˜λŠ” λŒ€μ‹  λ°˜λ³΅μžλ‘œλΆ€ν„° String 값을 Config μΈμŠ€ν„΄μŠ€λ‘œ 이동할 수 있음

πŸ€” λ¦¬ν„΄λœ 반볡자λ₯Ό 직접 μ‚¬μš©ν•˜λŠ” 방법

use std::{env, process};
use minigrep::Config;

fn main() {
    let config = Config::new(env::args()).unwrap_or_else(|err| {
        eprintln!("인수λ₯Ό κ΅¬λ¬ΈλΆ„μ„ν•˜λŠ” λ™μ•ˆ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {}", err);
        process::exit(1);
    });
    println!("검색어: {}\n파일 이름: {}", config.query, config.filename);

    if let Err(e) = minigrep::run(config) {
        eprintln!("μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ—λŸ¬: {}", e);
        process::exit(1);
    }
}
  • env::args ν•¨μˆ˜μ˜ 리턴값을 Config::new ν•¨μˆ˜μ— κ·ΈλŒ€λ‘œ 전달
impl Config {
    pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
  • 반볡자λ₯Ό μ‚¬μš©ν•˜λ„λ‘ μˆ˜μ •ν•œ Config::new ν•¨μˆ˜μ˜ μ‹œκ·Έλ‹ˆμ²˜
  • env::args ν•¨μˆ˜λŠ” std::env::Args νƒ€μž…μ˜ 반볡자λ₯Ό 리턴함
    • ν•΄λ‹Ή 반볡자λ₯Ό μˆœνšŒν•΄μ•Ό ν•˜λ―€λ‘œ κ°€λ³€ λ§€κ°œλ³€μˆ˜λ‘œ 선언함

πŸ€” 인덱슀 λŒ€μ‹  Iterator 트레이트의 λ©”μ„œλ“œ ν™œμš©ν•˜κΈ°

impl Config {
    pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
        args.next();
        Ok(Config {
            query: {
                match args.next() {
                    Some(arg) => arg,
                    None => return Err("검색어λ₯Ό 지정해야 ν•©λ‹ˆλ‹€."),
                }
            },
            filename: {
                match args.next() {
                    Some(arg) => arg,
                    None => return Err("파일λͺ…을 지정해야 ν•©λ‹ˆλ‹€."),
                }
            },
            case_sensitive: {
                env::var("CASE_INSENSITIVE").is_err()
            },
        })
    }
}
  • 반볡자 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μˆ˜μ •ν•œ Config::new ν•¨μˆ˜
  • env::args ν•¨μˆ˜κ°€ λ¦¬ν„΄ν•˜λŠ” κ°’μ˜ 첫 λ²ˆμ§ΈλŠ” ν”„λ‘œκ·Έλž¨μ˜ 이름
    • 이 값은 λ¬΄μ‹œ

πŸ€” 반볡자 μ–΄λŒ‘ν„°λ₯Ό μ΄μš©ν•΄ 더 κΉ”λ”ν•œ μ½”λ“œ μž‘μ„±ν•˜κΈ°

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let mut v = vec![];
    for l in contents.lines() {
        if l.contains(query) {
            v.push(l);
        }
    }
    v
}
  • 기쑴의 search ν•¨μˆ˜
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents.lines()
        .filter(|l| l.contains(query))
        .collect()
}
  • 반볡자 μ–΄λŒ‘ν„°λ₯Ό μ΄μš©ν•΄ λ‹€μ‹œ κ΅¬ν˜„ν•œ search ν•¨μˆ˜
  • ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ€ κ°€λ³€ μƒνƒœμ˜ 양을 μ΅œμ†Œν™”ν•΄μ„œ μ½”λ“œλ₯Ό 더 κΉ”λ”ν•˜κ²Œ μœ μ§€ν•˜λŠ” 데 도움이 됨
    • κ°€λ³€ μƒνƒœλ₯Ό μ œκ±°ν•˜λ©΄ 쀑간값을 μ €μž₯ν•  벑터λ₯Ό μ‚¬μš©ν•  ν•„μš”κ°€ μ—†μ–΄μ Έμ„œ λ‚˜μ€‘μ— κ²€μƒ‰μ˜ 병렬 싀행을 μ§€μ›ν•˜κΈ°λ„ μœ λ¦¬ν•¨
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents.lines()
        .filter(|l| l.to_lowercase().contains(&query.to_lowercase()))
        .collect()
}
  • 같은 λ°©μ‹μœΌλ‘œ λ‹€μ‹œ κ΅¬ν˜„ν•œ search_case_insensitive ν•¨μˆ˜

πŸ€” 루프와 반볡자의 μ„±λŠ₯ 비ꡐ

  • λ°˜λ³΅μžκ°€ κ³ μˆ˜μ€€μ˜ 좔상화λ₯Ό μ œκ³΅ν•˜κΈ°λŠ” ν•˜μ§€λ§Œ 직접 μž‘μ„±ν•˜λŠ” μ €μˆ˜μ€€μ˜ μ½”λ“œμ™€ 거의 같은 μ½”λ“œλ‘œ 컴파일됨
  • λ°˜λ³΅μžλŠ” 러슀트의 λ¬΄λΉ„μš© 좔상화(zero-cost abstractions) κΈ°λŠ₯ 쀑 ν•˜λ‚˜μž„
    • 좔상화λ₯Ό μ‚¬μš©ν•œλ‹€κ³  좔가적인 λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜μ§€ μ•ŠμŒ
fn main() {
    let buf: &mut [i32];
    let coefficients: [i64; 12];
    let qlp_shift: i16;

    for i in 12..buf.len() {
        let prediction = coefficients.iter()
            .zip(&buf[i-12..i])
            .map(|(&c, &s)| c*s as i64)
            .sum::<i64>() >> qlp_shift;
        let delta = buf[i];
        buf[i] = prediction as i32 + delta;
    }
}
  • prediction 값을 κ³„μ‚°ν•˜κΈ° μœ„ν•΄ coefficients λ°°μ—΄μ˜ 12개 값을 μˆœνšŒν•˜λ©΄μ„œ zip λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ buf에 μ €μž₯된 이전 12개 값을 μ΄μš©ν•΄ κ°’μ˜ μŒμ„ λ§Œλ“¬
    • 각 쌍의 값듀을 κ³±ν•˜κ³  κ·Έ κ²°κ³Όλ₯Ό λͺ¨λ‘ λ”ν•΄μ„œ qlp_shift λ³€μˆ˜μ— μ§€μ •λœ λΉ„νŠΈλ§ŒνΌ 였λ₯Έμͺ½μœΌλ‘œ 이동함
  • ν•΄λ‹Ή μ½”λ“œλŠ” κ°œλ°œμžκ°€ μ†μœΌλ‘œ μž‘μ„±ν•˜λŠ” 것과 같은 μ–΄μ…ˆλΈ”λ¦¬ μ½”λ“œλ‘œ 컴파일됨
    • coefficients λ°°μ—΄μ˜ 값을 μˆœνšŒν•˜λŠ” 데 ν•„μš”ν•œ λ£¨ν”„λŠ” μ‘΄μž¬ν•˜μ§€ μ•Šμ§€λ§Œ λŸ¬μŠ€νŠΈλŠ” 12개의 μ•„μ΄ν…œμ„ μˆœνšŒν•΄μ•Ό ν•œλ‹€λŠ” 것을 μ•Œκ³  μžˆμœΌλ―€λ‘œ 루프λ₯Ό 풀어냄
    • μ—¬κΈ°μ„œ ν’€μ–΄λ‚Έλ‹€λŠ” 것은 루프λ₯Ό μ œμ–΄ν•˜λŠ” μ½”λ“œμ˜ μ˜€λ²„ν—€λ“œλ₯Ό μ—†μ• κΈ° μœ„ν•΄ 루프λ₯Ό μ œκ±°ν•˜κ³  루프 μ•ˆμ—μ„œ μ‹€ν–‰λ˜λ˜ μ½”λ“œλ₯Ό ν•„μš”ν•œ 횟수만큼 λ°˜λ³΅ν•˜λŠ” μ½”λ“œλ₯Ό μƒμ„±ν•˜λŠ” 과정을 λœ»ν•¨
  • coefficients λ°°μ—΄μ˜ λͺ¨λ“  값듀은 λ ˆμ§€μŠ€ν„°μ— μ €μž₯됨
    • 값에 맀우 λΉ λ₯΄κ²Œ μ ‘κ·Ό κ°€λŠ₯
    • λ°°μ—΄ μ ‘κ·Ό μ‹œ λŸ°νƒ€μž„μ— 경계값 검사도 μ‹€ν–‰ν•˜μ§€ μ•ŠμŒ

Summary

  • ν΄λ‘œμ €μ™€ λ°˜λ³΅μžλŠ” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λ‘œλΆ€ν„° μ°¨μš©ν•œ κΈ°λŠ₯
  • ν΄λ‘œμ €μ™€ 반볡자의 κ΅¬ν˜„μ€ λŸ°νƒ€μž„ μ„±λŠ₯에 거의 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμŒ
    • λ¬΄λΉ„μš© 좔상화λ₯Ό λ‹¬μ„±ν•˜κΈ° μœ„ν•œ λ…Έλ ₯의 μΌν™˜
728x90
λ°˜μ‘ν˜•
Comments