İçeriğe geç
Educora
Orta18 dk7 / 10

Koleksiyonlar, closure'lar ve yineleyiciler

Verileri `Vec` ve `HashMap` içinde sakla, closure'lar yaz ve döngüleri `map`, `filter`, `collect` gibi yineleyici metotlarıyla kısa ve okunaklı zincirlere dönüştür.

Kendini test et
Bu derste öğreneceklerin
  • Bir Vec'e eleman eklemek, çıkarmak ve onu üç yolla dolaşmak
  • HashMap ile bir sayaç kurmak ve sonucu kararlı bir sırayla yazdırmak
  • Çevresindeki değişkenleri yakalayan closure'lar yazmak
  • map, filter, sum ve collect ile yineleyici zincirleri kurmak

Öğretmen her dersten sonra deftere yeni notlar ekler; liste büyür. Sonra hangi notun kaç kez yazıldığını saymak ister; bu da bir “anahtar → sayı” sözlüğüdür. Gerçek programların çoğu tam olarak bu tür koleksiyonlarla çalışır. Rust'ta bunun için Vec ve HashMap, onları işlemek için de güçlü yineleyiciler (iterator) vardır.

Vec — büyüyen liste

Vec<T>, öbekte saklanan, aynı türde elemanlardan oluşan, boyutu değişebilen bir listedir. vec![...] makrosuyla ya da Vec::new() ile oluşturulur. push sona eleman ekler, pop sonuncuyu çıkarıp bir Option döndürür, len ise uzunluğu verir. v[i] sınır dışında panikler, v.get(i) ise None döndürür.

Rust
fn main() {
    let mut scores = vec![72, 95, 88];
    scores.push(64);
    println!("{:?} len={}", scores, scores.len());
    println!("first = {}", scores[0]);
    println!("get(10) = {:?}", scores.get(10));

    if let Some(last) = scores.pop() {
        println!("popped {last}");
    }
    for s in &mut scores {
        *s += 5;
    }
    println!("{:?}", scores);
}
Beklenen çıktı
[72, 95, 88, 64] len=4
first = 72
get(10) = None
popped 64
[77, 100, 93]
for s in &mut scores her elemana değiştirilebilir bir referans verir; *s referansın arkasındaki değere erişir.
DöngüElemanDöngüden sonra v
for x in &v&T — okumakullanılabilir
for x in &mut v&mut T — değiştirmekullanılabilir
for x in vT — sahiplik alınırtaşındı, kullanılamaz

HashMap — anahtarlar ve değerler

HashMap<K, V>, her anahtara bir değer eşler ve std::collections içinden içe aktarılması gerekir. insert bir çift ekler, get ise Option<&V> döndürür. Sayaç kurmanın en kısa yolu entry API'dir: entry(anahtar).or_insert(0), anahtar yoksa onu 0 ile oluşturur ve değerine değiştirilebilir bir referans döndürür.

Rust
use std::collections::HashMap;

fn main() {
    let text = "the cat and the dog and the bird";
    let mut counts: HashMap<&str, u32> = HashMap::new();
    for word in text.split_whitespace() {
        *counts.entry(word).or_insert(0) += 1;
    }
    println!("the: {:?}", counts.get("the"));
    println!("fish: {:?}", counts.get("fish"));

    let mut pairs: Vec<(&str, u32)> = counts.into_iter().collect();
    pairs.sort();
    println!("{:?}", pairs);
}
Beklenen çıktı
the: Some(3)
fish: None
[("and", 2), ("bird", 1), ("cat", 1), ("dog", 1), ("the", 3)]
split_whitespace() metni boşluklardan kelimelere böler. Sonucu kararlı bir sırayla göstermek için çiftleri bir listeye toplayıp sıraladık.

Closure'lar

Closure, yerinde yazılan adsız bir fonksiyondur: |parametreler| gövde. Parametre türlerini genellikle yazmak gerekmez; derleyici onları kullanımdan çıkarır. Closure'ın temel özelliği çevresindeki değişkenleri yakalamasıdır: aşağıda add_bonus, bonus'u okur; click ise clicks'i değiştirir, bu yüzden kendisi de mut olarak bildirilmiştir.

Rust
fn main() {
    let bonus = 10;
    let add_bonus = |score: i32| score + bonus;
    let double = |x| x * 2;
    println!("{}", add_bonus(80));
    println!("{}", double(21));

    let mut clicks = 0;
    let mut click = || clicks += 1;
    click();
    click();
    println!("clicks = {clicks}");
}
Beklenen çıktı
90
42
clicks = 2

Yineleyiciler: map, filter, collect

v.iter(), elemanları tek tek veren bir yineleyici oluşturur. map (her elemanı dönüştür) ve filter (koşula uyanları tut) gibi bağdaştırıcılar tembeldir: kendileri hiçbir şey hesaplamaz, yalnızca bir plan kurar. İş, collect, sum, count ya da max gibi sonlandırıcı bir metot çağrıldığında başlar. collect'e sonucun türünü belirtmek gerekir, örneğin Vec<i32>.

Rust
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6];

    let squares: Vec<i32> = numbers.iter().map(|n| n * n).collect();
    let evens: Vec<i32> = numbers.iter().copied().filter(|n| n % 2 == 0).collect();
    let total: i32 = numbers.iter().sum();
    let max = numbers.iter().max();

    println!("{:?}", squares);
    println!("{:?}", evens);
    println!("total = {total}, max = {max:?}");
    println!("{:?}", numbers);
}
Beklenen çıktı
[1, 4, 9, 16, 25, 36]
[2, 4, 6]
total = 21, max = Some(6)
[1, 2, 3, 4, 5, 6]
iter() elemanları ödünç alır; bu yüzden numbers sonunda değişmeden kalır. copied(), &i32 referanslarını i32 değerlerine çevirir. max boş bir listede None döndürebileceği için sonucu bir Option'dır.
Döngüyle
let names = vec!["aysel", "ali", "leyla", "rauf"];
let mut result = Vec::new();
for name in &names {
    if name.len() > 3 {
        result.push(name.to_uppercase());
    }
}
Yineleyici zinciriyle
let names = vec!["aysel", "ali", "leyla", "rauf"];
let result: Vec<String> = names
    .iter()
    .filter(|name| name.len() > 3)
    .map(|name| name.to_uppercase())
    .collect();
İki sürüm de ["AYSEL", "LEYLA", "RAUF"] üretir. Zincir yukarıdan aşağıya “ne yapıyoruz” diye okunur ve result, mut olmadan oluşturulur.
MetotNe yapar
map(f)her elemanı f ile dönüştürür
filter(p)p'nin doğru olduğu elemanları tutar
enumerate()her elemana bir indeks ekler
zip(other)iki yineleyiciyi çift çift birleştirir
take(n), skip(n)ilk n elemanı alır / atlar
sum(), count(), max()toplam, sayı, en büyük
any(p), all(p), find(p)herhangi biri uyuyor mu / hepsi uyuyor mu / ilkini bul
collect()sonucu bir koleksiyonda toplar

Önemli noktalar

  • Vec<T> büyüyebilen bir listedir: push, pop, len; get(i) sınır dışında None döndürür.
  • HashMap ile sayaç: *map.entry(k).or_insert(0) += 1; yazdırmadan önce sırala ya da BTreeMap kullan.
  • Closure, |x| ifade biçimindedir ve çevresindeki değişkenleri yakalayabilir.
  • map ve filter tembeldir; iş collect, sum ya da count gibi sonlandırıcı bir metotla başlar.
  • iter() ödünç alır, into_iter() ise sahipliği alır.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
Üç elemanlı bir Vec için v.get(10) ne döndürür?