---
title: "Yineleyici Trait'i"
source: 'https://academia.sh/tr/kurslar/rust-soyutlama/yineleyici-traiti'
course: "Trait'ler, Genellikler ve Hata Yönetimi"
language: tr
updated: '2026-09-13T05:09:26+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir kaynak üzerinde dolaşmanın tek bir sözleşmeye — sırada bir sonraki değeri isteyen çağrıya — indirgendiğini kendi yazdığı bir sözleşme gerçekleştirimiyle gösterir'
    - 'Kurulan ama tüketilmeyen bir zincirin gövdesinin hiç koşmadığını, aynı kaynağın tüketilen bir eşdeğeriyle karşılaştırarak ölçer'
    - 'Zincir kurmanın kendisiyle zincirin ilerlemesini birbirinden ayırt eder'
---

# Yineleyici Trait'i

Bir kaynağın üzerinde dolaşmanın tek bir sözleşmeye — sırada bir sonraki değeri isteyen tek bir çağrıya — indirgendiği ve bu sözleşmenin yalnızca istendiğinde ilerlediği ölçülüyor: kurulan bir zincir hiç tüketilmezse gövdesi hiç koşmuyor.

Önceki ders tek bir kapanışın ne zaman koştuğunu ölçtü: saklanan bir gövde, çağrılmadığı
sürece hiç koşmuyordu. Bu ders aynı soruyu tek bir kapanıştan bir kaynağın tamamına
taşıyor. Bir dizi, bir aralık, bir dizgi — hepsi üzerinde "dolaşmak" farklı bir işlem gibi
görünür, ama Rust bunların hepsini tek bir sözleşmeye indirger: sırada bir sonraki değeri
isteyen tek bir çağrı. Bu ders o sözleşmenin kendisini yazıp, dolaşmanın gerçekte bu tek
çağrının tekrarı olduğunu ve bir kaynağın üzerinde kurulmuş bir zincirin bu çağrı hiç
gelmeden koşum defterine hiç girmediğini ölçüyor. Ölçülen, kaynağın türü ya da içeriği
değil; sözleşmenin yönteminin ne zaman ve kaç kez işletildiğidir. Bu, kapanışlar
konusundaki ölçümün doğal bir uzantısı: orada tek bir gövdenin saklanma biçimi
belirleyiciydi, burada birçok kapanışın birbirine bağlandığı bir sözleşmenin kendisi
belirleyici. Sözleşme değişmeden kalırken, onu kim gerçekleştirdiği — bir dizi, bir
aralık, ya da bu derste elle yazılan `Sayici` — değişebilir; ölçülen sayı bu seçimden
bağımsızdır.

## Dolaşmanın Tek Bir Sözleşmeye İndirgenmesi

Bir `for` döngüsü, bir dönüşüm zinciri, bir toplama çağrısı — kaynak metinde birbirinden
çok farklı görünen bu yazımların hepsi, altta aynı tek yönteme iniyor: sırada bir sonraki
değeri iste, yoksa dur. Bu yöntemin adı ve imzası tek bir sözleşmede toplanıyor; bir tip bu
sözleşmeyi gerçekleştirdiğinde, üzerinde dolaşılabilir hale geliyor. Sözleşmenin kendisi
ne kaynağın nasıl saklandığını, ne de kaç elemanı olduğunu söylüyor — yalnızca "bir
sonrakini ver" sorusuna nasıl yanıt vereceğini.

Standart kitaplığın kendi kaynakları (bir büyüyen dizi, bir aralık) bu sözleşmeyi zaten
gerçekleştiriyor, ama gerçekleştirimin içine bir sayaç yerleştirilemez — sözleşmenin
yöntemi kaç kez çağrıldı diye doğrudan sorulamaz. Bu yüzden aşağıdaki koşum, sözleşmeyi
kendi yazdığı küçük bir tipte gerçekleştiriyor: `Sayici`, tek bir sayaç tutan ve isteneni
bir bir üreten bir kaynak. Sözleşmenin kendisi standart kitaplığınkiyle birebir aynı;
farklı olan yalnızca, yöntemin her çağrıldığında bunu deftere yazması.

**YN5.** — "üç elemanlı bir kaynak üzerinde dolaşmanın, kaynağın kendi sözleşme
gerçekleştiriminin tek bir yöntemine dört kez uğradığı" iddiası, aşağıdaki koşumla
doğrulanıyor.

```rust
// sayici_dolasim.rs — dolasmanin tek bir sonraki-deger cagrisina indirgendigini olcuyor
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

type Defter = Rc<RefCell<BTreeMap<String, u32>>>;

fn say(defter: &Defter, ad: &str) {
    *defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}

fn kere(defter: &Defter, ad: &str) -> u32 {
    *defter.borrow().get(ad).unwrap_or(&0)
}

struct Sayici {
    su_an: u32,
    sinir: u32,
    defter: Defter,
}

impl Iterator for Sayici {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        say(&self.defter, "sonraki-deger-cagrisi");
        if self.su_an < self.sinir {
            self.su_an += 1;
            Some(self.su_an)
        } else {
            None
        }
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));
    let sayici = Sayici { su_an: 0, sinir: 3, defter: Rc::clone(&defter) };

    let mut toplam = 0;
    for deger in sayici {
        toplam += deger;
    }

    println!("toplam: {}", toplam);
    println!("sonraki deger cagrisi sayisi: {}", kere(&defter, "sonraki-deger-cagrisi"));
}
```

```
toplam: 6
sonraki deger cagrisi sayisi: 4
```

`Sayici`, sözleşmenin tek yöntemini gerçekleştiriyor: bir sonraki değer varsa onu veriyor
ve kendi durumunu bir ilerletiyor, yoksa boş bir yanıt döndürüyor. Kaynak metinde `for`
döngüsü tek bir yazım gibi görünse de, koşumda bu yöntem üç elemanlı `Sayici` üzerinde dört
kez çağrılıyor: üç kez bir değerle, bir kez de "artık yok" yanıtıyla. Döngü bu dördüncü
çağrıyı görene kadar durmuyor — kendisi eleman saymıyor, yalnızca yanıtı boş olana kadar
sormaya devam ediyor. Toplamın altı çıkması (1 + 2 + 3) ile çağrı sayısının dört olması
aynı koşumun iki farklı yüzü: biri elemanların değerini, öbürü sözleşmenin kaç kez
işletildiğini gösteriyor. Bu ölçü, M08/K04'ün ölçtüğü "adımı hangi iş parçacığı
koşturuyor" sorusuyla karışmaz: burada tek bir iş parçacığı var, soru yalnızca sözleşmenin
kaç kez işletildiğidir.

Dördüncü çağrı, kaynak metinde hiçbir yerde açıkça yazılmıyor — `for` döngüsünün kendisi bu
çağrıyı üretiyor, "artık değer yok" yanıtını görene kadar sormaya devam ederek. Bu, dolaşan
tarafın (döngünün) kaynağın kaç eleman taşıdığını önceden bilmesi gerekmediği anlamına
geliyor: `Sayici`nin sınırı üç olarak kuruldu, ama döngü bu sınırı hiç okumadı, yalnızca
yanıtları izledi. Sözleşme, kaynağın büyüklüğünü kaynağın kendisine saklı tutuyor.

Sözleşmenin tek yöntemi, kaynağın tamamının dolaşılmasını da zorunlu kılmıyor — yalnızca
kaç kez istenirse o kadar ilerliyor. Aynı `Sayici`, sınırı beş olacak biçimde kurulup
yalnızca iki kez sorguluyor.

**YN6.** — "beş elemanlık bir kaynağın yalnızca ilk iki değeri istendiğinde, sözleşmenin
yönteminin beş değil iki kez çağrıldığı" iddiası, aşağıdaki koşumla doğrulanıyor.

```rust
// kismi_tuketim.rs — bir yineleyici sonuna kadar tuketilmeden de birakilabiliyor
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

type Defter = Rc<RefCell<BTreeMap<String, u32>>>;

fn say(defter: &Defter, ad: &str) {
    *defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}

fn kere(defter: &Defter, ad: &str) -> u32 {
    *defter.borrow().get(ad).unwrap_or(&0)
}

struct Sayici {
    su_an: u32,
    sinir: u32,
    defter: Defter,
}

impl Iterator for Sayici {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        say(&self.defter, "kismi-sonraki-deger-cagrisi");
        if self.su_an < self.sinir {
            self.su_an += 1;
            Some(self.su_an)
        } else {
            None
        }
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));
    let mut sayici = Sayici { su_an: 0, sinir: 5, defter: Rc::clone(&defter) };

    let ilk = sayici.next();
    let ikinci = sayici.next();

    println!("ilk iki deger: {:?}, {:?}", ilk, ikinci);
    println!("sinir bes iken cagri sayisi: {}", kere(&defter, "kismi-sonraki-deger-cagrisi"));
}
```

```
ilk iki deger: Some(1), Some(2)
sinir bes iken cagri sayisi: 2
```

`sayici` beş değere kadar ilerleyebilecek biçimde kuruldu, ama yalnızca iki kez açıkça
sorgulandı ve kalan üç değere hiç uğranmadı — `sayici` burada kapsamının sonunda sessizce
bırakılıyor. Sözleşmenin yöntemi, kaynağın "bitmesini" değil, "istenmesini" bekliyor:
kaynak beş eleman taşısa da, taşıdığı sayı çağrı sayısını belirlemiyor, yalnızca üst sınırı
belirliyor. Bu gözlem sıradaki dersin eksenini önceden kuruyor: bir kaynağın uzunluğu ile
üzerinde çalışan gövdenin kaç kez koştuğu aynı sayı değildir.

Bu koşumda yöntem elle, iki ayrı satırda çağrıldı; bir önceki koşumda ise aynı yöntemi bir
döngü çağırıyordu. İkisi arasındaki fark yalnızca çağıranın kimliğinde: birinde çağıran
kod bizim yazdığımız `main`, öbüründe çağıran kod `for` döngüsünün kendisi. Sözleşmenin
yöntemi her iki durumda da aynı imzayı taşıyor ve aynı biçimde yanıt veriyor — kimin
çağırdığı, sözleşmenin davranışını değiştirmiyor, yalnızca çağrının kaynak metinde nerede
göründüğünü değiştiriyor. Bu, sözleşmenin "tek" olmasının tam anlamı: dolaşımın hangi
yazımla ifade edildiğinden bağımsız, altta hep aynı yönteme iniyor.

Sözleşmenin bu tekliği, bir dolaşım biçiminin başka bir dolaşım biçimine dönüştürülmesini
de basitleştiriyor: bir dönüşüm zinciri ya da bir arama çağrısı yazıldığında, bunların
hepsi aynı sözleşmenin üstüne kuruluyor, ayrı bir dolaşım kuralı öğrenmeye gerek kalmıyor.
Bu üst yöntemlerin çoğu, kursun açılış dersinde ölçülen türden varsayılan gövdelerdir —
kendileri `next` çağrısını içermez, `next`i tekrar tekrar çağıran hazır bir gövdeyi
devralırlar; orada ölçülen, bir varsayılan gövdenin onu yeniden yazan bir tip için hiç
koşmadığıydı, burada ölçülen ise aynı mekanizmanın dolaşım sözleşmesindeki somut bir
örneği. Ne var ki bu sözleşmenin var olması, dolaşmanın kaynak kodda yazılmasıyla koşumda
gerçekleşmesinin aynı an olduğu anlamına gelmiyor — bu ayrım sıradaki ölçünün konusu.

## Kurulmuş Ama Hiç Tüketilmemiş Zincir

Bir kaynak üzerinde bir dönüşüm tanımlamak, o dönüşümü çalıştırmakla aynı şey değildir. Bir
önceki ölçüm sözleşmenin yöntemini elle çağırdı; bu ölçüm aynı sözleşmenin üstüne kurulan,
kaynak metinde çok daha sık görülen bir yazımı — bir dönüşüm zinciri — ele alıyor. Bir
dönüşüm zinciri yazmak (`.map(...)` gibi), kaynağı ve bir kapanışı bir araya getirip yeni
bir kaynak üreten bir çağrıdır; ürettiği şey de kendisi sözleşmeyi gerçekleştiren bir
değerdir. Kursun ölçüm çekirdeğindeki bir satır, dört elemanlı bir kaynağı dönüştüren bir
zincir kuruyor ama bu zinciri hiçbir yerde tüketmiyor — sonucu ne bir döngüye veriyor, ne
bir listeye topluyor, ne de bir toplama çağrısına yolluyor. Zincirin bu haliyle koşup
koşmadığı, tembel değerlendirme kavramının bir uygulamasıdır; bu kavram Programlama
Temelleri kursunda kuruldu ve burada yeniden anlatılmıyor, yalnızca kaç kez koştuğu
sayılıyor.

**YN7.** — "aynı dört elemanlı kaynağın bir kez hiç tüketilmeden, bir kez toplama
çağrısıyla tüketilerek kurulduğunda, tüketilmeyen gövdenin sıfır, tüketilenin dört kez
koştuğu" iddiası, aşağıdaki koşumla doğrulanıyor.

```rust
// tuketilmeyen_ve_tuketilen.rs — ayni kaynak bir kez tuketilmeden, bir kez tuketilerek kuruluyor
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

type Defter = Rc<RefCell<BTreeMap<String, u32>>>;

fn say(defter: &Defter, ad: &str) {
    *defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}

fn kere(defter: &Defter, ad: &str) -> u32 {
    *defter.borrow().get(ad).unwrap_or(&0)
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));

    // tuketilmeyen: kursun olcum cekirdegindeki ayni kesit, hic tuketilmiyor
    let _tembel = vec![1, 2, 3, 4].into_iter().map(|x| {
        say(&defter, "tuketilmeyen-zincir");
        x * 2
    });

    // ayni kaynak, bu kez toplama cagrisiyla tuketiliyor
    let toplam: i32 = vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| {
            say(&defter, "tuketilen-esdeger-zincir");
            x * 2
        })
        .sum();

    println!("tuketilmeyen govde kac kez kosti: {}", kere(&defter, "tuketilmeyen-zincir"));
    println!(
        "tuketilen govde kac kez kosti: {} (toplam {})",
        kere(&defter, "tuketilen-esdeger-zincir"),
        toplam
    );
}
```

```
tuketilmeyen govde kac kez kosti: 0
tuketilen govde kac kez kosti: 4 (toplam 20)
```

İki zincirin kaynak metni aynı biçimde başlıyor: aynı dört elemanlı kaynak, aynı dönüşüm
gövdesi. Fark yalnızca sonda: birincisi bir adın altında saklanıp bırakılıyor, ikincisi bir
toplama çağrısına veriliyor. `tuketilmeyen-zincir` sayacı koşumun sonuna kadar sıfırda
kalıyor — kursun bağlayıcı tablosunda bu satır **hiç** sınıfına düşüyor. Eşdeğer zincir
tüketildiğinde ise dönüşüm gövdesi dört elemanın her biri için bir kez, toplam dört kez
koşuyor. Kurulmuş bir zincirin kaynakta durması, sözleşmenin sırada bir sonraki değeri iste
çağrısının hiç gelmediği anlamına geliyor; çağrı gelmeden gövde koşmuyor.

Bu iki koşumun tek farkı zincirin kaynak metninde değil, zincirin sonunda ne bulunduğunda.
`.sum()` çağrısı, sözleşmenin yöntemini kaynak bitene kadar tekrar tekrar çağıran bir
tüketicidir; `_tembel` adının altına bırakılan zincirde böyle bir tüketici hiç yok. Bir
zincirin dönüşüm gövdesini yazmak, o gövdeyi koşum defterine kaydetmenin yalnızca ön
koşuludur — yeterli koşulu, zincirin ucuna bir tüketici bağlanmasıdır.

Bu fark, kaynak metni okuyarak da fark edilebilir: `_tembel` adı altını çizen alt çizgi,
Rust'ın "bu ad kullanılmıyor" uyarısını susturmak için oradadır — kapanışın önceki derste
görülen `_kapanis` adıyla aynı işaret. Bir zincirin kurulup hiç kullanılmaması, kaynak
metinde de küçük bir iz bırakıyor: adı okunmayan bir bağlama. Tüketilen zincirde ise sonuç
`toplam` adına bağlanıp yazdırma çağrısında okunuyor; ad kullanılmadan kalmıyor.

## Sınırlayıcı Ölçüm

Tüketilmeyen bir zincirin gövde koşum sayacının sıfır olması, o zincirin bedelsiz olduğu
anlamına gelmez. `map` çağrısı, kaynağı ve dönüşüm kapanışını saran bir yapı kuruyor; bu
yapı `_tembel` adı altında bellekte duruyor, tıpkı önceki dersteki hiç çağrılmayan bir
kapanışın kendisi gibi. Kurulan bu yapının kendisi bir değerdir ve bir yer kaplar — ama bu
yer kaplama, koşum defterinin ölçtüğü "gövde kaç kez koştu" sorusunun kapsamına girmez.
Defter yalnızca dönüşüm kapanışının içindeki çağrıyı sayıyor; zincirin kurulma anında
kapladığı yapıyı saymıyor. Bu ders o bedeli ölçmeye kalkmıyor, yalnızca var olduğunu
kaydediyor. Bu, önceki dersin sınırlayıcı ölçümüyle birebir aynı gözlemin, tek bir
kapanıştan bir kapanış zincirine taşınmış hâlidir.

Aynı sınır, `Sayici` örneğindeki kısmi tüketim ölçümü için de geçerli. Sınırı beş olan bir
kaynağın yalnızca iki değeri istenip geri kalan üçünün hiç istenmemesi, o üç değerin
üretilmediği anlamına geliyor — ama kaynağın kendisinin kurulma bedeli, bu sınırın nerede
kesildiğinden bağımsız olarak zaten ödendi. Ölçülen sayı, kurulma anındaki değil, sonraki
istekteki maliyeti yansıtıyor.

Bu iki gözlem birlikte, kaç kez koştu sorusunun sınırlarını çiziyor: sayaç, sözleşmenin
yönteminin ne zaman çağrıldığını kesin olarak söylüyor, ama o yöntemi barındıran yapının
ne zaman kurulduğunu, ne kadar yer kapladığını söylemiyor. Bir zincir kurulur, bir kısmı
istenir, kalanı hiç istenmeden bırakılır — üç ayrı an, üç ayrı soru ve bu dersin ölçtüğü
sayı bunlardan yalnızca birine, çağrı anına yanıt veriyor. Kurulma anını ve yer kaplamayı
ölçmek isteyen bir soru, farklı bir araç ister; bu kurs o aracı yazmıyor, yalnızca hangi
sorunun bu sayının kapsamı dışında kaldığını açıkça belirtiyor.

## Özet

- Bir kaynak üzerinde dolaşmak, kaynağın kendi sözleşmesinin tek bir yöntemine tekrar tekrar
  uğramaya indirgeniyor; üç elemanlı bir kaynakta bu yöntem dört kez çağrılıyor.
- Sözleşmenin kendisi kaynağın saklanma biçiminden bağımsızdır; yalnızca "bir sonrakini
  ver" sorusuna nasıl yanıt vereceğini tanımlar.
- Kursun ölçüm çekirdeğindeki `tuketilmeyen-zincir` gövdesi bu koşumda **hiç** çalışmadı —
  aynı kaynağın tüketilen eşdeğeri dört kez çalıştı.
- Zincir kurmak ile zincirin ilerlemesi ayrı olaylardır; kurulma anında sözleşmenin
  yöntemine hiç uğranmaz; beş elemanlık bir kaynağın yalnızca iki değeri istenirse
  sözleşmenin yöntemi de yalnızca iki kez çağrılır.
- Tembel değerlendirmenin kendisi bu derste yeniden kurulmadı; yalnızca kaç kez koştuğu
  sayıldı.
- Kurulmuş ama tüketilmeyen bir zincir bedelsiz değildir — bu bedel gövde koşum sayacının
  ölçtüğü şey değildir; sayaç yalnızca çağrı anını, kurulma anını değil ölçer.

## Sonraki Adım

Bu derste bir zincirin hiç tüketilmemesi ile tüketilmesi arasındaki fark, tek bir dönüşüm
adımı üzerinden ölçüldü: sıfıra karşı dört. Ama "tüketilmek" tek bir anlam taşımıyor —
kısmi tüketim ölçümünde görüldüğü gibi, bir kaynağın ne kadarının istendiği de sözleşmenin
yöntemine kaç kez uğranacağını belirliyor. Bu derste iki uç durum görüldü: hiç istenmemek
(sıfır) ve tamamı istenmek (dört). Sıradaki ders aynı kaynağı, aynı dönüşüm gövdesini alıp
zincirin ucuna farklı tüketiciler koyuyor ve bu kez zincirin uzunluğunun değil, tüketicinin
gövdenin kaç kez koşacağını belirlediğini gösteriyor — bir tüketici kaynağın tamamını
isteyebilir, bir başkası ilk uygun değeri bulunca durabilir; ikisi de aynı dört elemanlı
kaynaktan başlayacak, ama biri uçlardan birine, öbürü ortasında bir yere düşecek bir sayı
üretecek. Bu iki ders bir arada, "tüketmek" sözcüğünün aslında bir uçtan öbürüne uzanan bir
aralığı kapsadığını gösteriyor: hiç, kısmen, tamamen.
