iter::from_fn în Rust

Creează un iterator dintr-un closure: fiecare apel al closure-ului dă următorul element, iar None oprește iteratorul.

Sintaxă
pub fn from_fn<T, F>(f: F) -> FromFn<F>
where F: FnMut() -> Option<T>

Ce face iter::from_fn

std::iter::from_fn(|| ...) este cel mai rapid mod de a face un iterator propriu fără să scrii o structură și un impl Iterator. Starea (contoare, poziții) stă în variabilele capturate de closure, de obicei cu move. Closure-ul returnează Some(valoare) pentru fiecare element și None când s-a terminat.

Dacă closure-ul nu returnează niciodată None, iteratorul este infinit și trebuie limitat cu take. Pentru șiruri în care fiecare element se calculează din cel dinainte, successors e mai potrivit.

Parametri

Parametru Descriere
f Closure FnMut() -> Option<T>, apelat pentru fiecare element.

Ce returnează

Un iterator FromFn.

Exemple

Exemplul 1: Numerotare pentru bonuri

use std::iter::from_fn;

fn main() {
    let mut numar = 1000;
    let bonuri = from_fn(move || {
        numar += 1;
        if numar <= 1005 { Some(format!("BON-{numar}")) } else { None }
    });
    println!("{:?}", bonuri.collect::<Vec<_>>());
}

Rezultat

["BON-1001", "BON-1002", "BON-1003", "BON-1004", "BON-1005"]

Exemplul 2: Șirul lui Fibonacci

Iteratorul este infinit; take_while îl oprește.

use std::iter::from_fn;

fn main() {
    let (mut a, mut b) = (0u64, 1u64);
    let fibonacci = from_fn(move || {
        let urmator = a;
        (a, b) = (b, a + b);
        Some(urmator)
    });
    let sub_100: Vec<u64> = fibonacci.take_while(|&x| x < 100).collect();
    println!("{:?}", sub_100);
}

Rezultat

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

Exemplul 3: Bucăți de text de lungime fixă

use std::iter::from_fn;

fn main() {
    let mut rest = "RO49AAAA1B31007593840000";
    let grupuri: Vec<&str> = from_fn(|| {
        if rest.is_empty() {
            return None;
        }
        let (bucata, r) = rest.split_at(rest.len().min(4));
        rest = r;
        Some(bucata)
    })
    .collect();
    println!("{}", grupuri.join(" "));
}

Rezultat

RO49 AAAA 1B31 0075 9384 0000

Greșeli frecvente

  • Uiți move când returnezi iteratorul dintr-o funcție: closure-ul împrumută variabile locale care dispar (closure may outlive the current function).
  • Closure-ul nu returnează niciodată None și apoi apelezi collect: programul nu se termină. Limitează cu take sau take_while.

Comenzi înrudite

  • iter::successors: Creează un șir în care fiecare element se calculează din cel dinainte; se oprește când funcția returnează None.
  • Iterator: Trait-ul care descrie orice șir de valori produse pe rând: next() dă următoarea valoare, sau None la final.
  • Fn, FnMut și FnOnce: Cele trei trait-uri ale closure-urilor: Fn doar citește ce a capturat, FnMut modifică, FnOnce consumă și poate fi apelat o singură dată.
  • Iterator::take: take(n) produce cel mult primele n elemente; skip(n) sare peste primele n și produce restul.