FromIterator în Rust

Trait-ul tipurilor care pot fi construite dintr-un iterator; collect() îl folosește pentru a crea colecția cerută.

Sintaxă
pub trait FromIterator<A>: Sized {
    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}

Ce face FromIterator

FromIterator<A> spune că un tip poate fi construit dintr-un șir de valori de tip A. it.collect::<X>() este doar o formă comodă pentru X::from_iter(it). Biblioteca standard îl implementează pentru toate colecțiile, pentru String, Box<[T]>, Result, Option, () și altele.

Poți apela și direct Vec::from_iter(1..4) sau String::from_iter(['a', 'b']); trait-ul este în preludiu, deci nu are nevoie de use. Implementându-l pentru un tip propriu, îl faci compatibil cu collect().

Ce returnează

from_iter returnează o valoare nouă de tipul Self.

Exemple

Exemplul 1: from_iter apelat direct

use std::collections::VecDeque;

fn main() {
    let v = Vec::from_iter(1..=4);
    let s = String::from_iter(['R', 'u', 's', 't']);
    let c = VecDeque::from_iter(["Ana", "Mihai"]);
    println!("{:?} {:?} {:?}", v, s, c);
}

Rezultat

[1, 2, 3, 4] "Rust" ["Ana", "Mihai"]

Exemplul 2: collect() într-un tip propriu

Implementăm FromIterator<i64> pentru o structură de statistici. De acum, orice iterator de i64 poate fi colectat în ea.

struct Statistici {
    numar: usize,
    suma: i64,
    minim: i64,
    maxim: i64,
}

impl FromIterator<i64> for Statistici {
    fn from_iter<I: IntoIterator<Item = i64>>(iter: I) -> Self {
        let mut s = Statistici { numar: 0, suma: 0, minim: i64::MAX, maxim: i64::MIN };
        for x in iter {
            s.numar += 1;
            s.suma += x;
            s.minim = s.minim.min(x);
            s.maxim = s.maxim.max(x);
        }
        s
    }
}

fn main() {
    let temperaturi = [4, -2, 9, 7, 12];
    let s: Statistici = temperaturi.into_iter().collect();
    println!("{} valori, suma {}, între {} și {}", s.numar, s.suma, s.minim, s.maxim);

    let pare: Statistici = (1..=10).filter(|x| x % 2 == 0).collect();
    println!("pare: {} valori, suma {}", pare.numar, pare.suma);
}

Rezultat

5 valori, suma 30, între -2 și 12
pare: 5 valori, suma 30

Greșeli frecvente

  • Colectezi într-un tip pentru care nu există FromIterator cu acel tip de element: a value of type `X` cannot be built from an iterator over elements of type `Y`. Transformă elementele întâi (map, copied) sau implementează trait-ul.
  • Confunzi FromIterator cu From: Vec::from([1, 2]) folosește From (din tablou), Vec::from_iter(..) primește orice iterator.

Comenzi înrudite

  • Iterator::collect: Consumă iteratorul și adună valorile într-o colecție: Vec, String, HashMap, HashSet, chiar Result sau Option.
  • IntoIterator: Trait-ul tipurilor care pot fi transformate într-un iterator; este ce folosește bucla for pentru a parcurge o valoare.
  • Iterator: Trait-ul care descrie orice șir de valori produse pe rând: next() dă următoarea valoare, sau None la final.