---
title: 'Yineleyici Bağdaştırıcıları'
source: 'https://academia.sh/tr/kurslar/rust-soyutlama/yineleyici-bagdasticilari'
course: "Trait'ler, Genellikler ve Hata Yönetimi"
language: tr
updated: '2026-10-21T05:03:44+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Aynı kaynak ve aynı dönüşüm gövdesiyle kurulan iki zincirin, yalnızca ucundaki tüketiciye göre farklı sayıda koştuğunu ölçerek gösterir'
    - 'Zincirin uzunluğu ile tüketicinin istediği miktarı birbirinden ayırt eder'
    - 'İki bağdaştırıcı zincirlendiğinde gövdelerin eleman başına sırayla mı yoksa bağdaştırıcı başına toplu mu koştuğunu bir kayıtla ölçer'
---

# Yineleyici Bağdaştırıcıları

Aynı dört elemanlı kaynaktan başlayan iki zincirin kaynak metni neredeyse aynı, ama biri gövdeyi her elemanda, öbürü yalnız gerektiği kadar koşturuyor: sayıyı belirleyenin zincirin uzunluğu değil ucuna bağlanan tüketici olduğu ve zincirlenen bağdaştırıcıların gövdelerinin eleman başına sırayla koştuğu ölçülüyor.

Önceki ders bir zincirin hiç tüketilmemesi ile tamamen tüketilmesi arasındaki iki uca
baktı: sıfır ve dört. Ama bu iki uç, "tüketilmek"in taşıdığı tüm olasılıkları
tüketmiyordu — bir kaynağın tamamı istenmeden de, hiç istenmeden de tüketilebileceği bir
orta hâl vardı. Bu ders aynı kaynağı, aynı dönüşüm gövdesini alıp zincirin ucuna farklı
tüketiciler bağlıyor ve ortaya çıkan sayının zincirin uzunluğundan değil, tüketicinin ne
kadar istediğinden geldiğini gösteriyor. İkinci ölçüm ise tek bir bağdaştırıcıdan iki
bağdaştırıcıya geçiyor: iki dönüşüm zincirlendiğinde, gövdeler bir sırayla mı, yoksa bir
başka sırayla mı koşuyor — bu sıra kaynak metinde açıkça yazılı değil, yalnızca koşumdan
okunabiliyor. Bu konunun adı "bağdaştırıcı" olan `map` gibi çağrıları anıyor; bu ders o
adın neden uygun olduğunu sayarak gösteriyor — bir bağdaştırıcı, kaynağı değiştirmeden
onu sarıp aynı sözleşmeyi taşıyan yeni bir kaynağa çeviriyor.

## Aynı Kaynak, Farklı Tüketici, Farklı Sayı

Bir dönüşüm zincirinin kaynak metni, zincirin ucuna hangi tüketicinin bağlandığını
söylemeden önce kaç kez koşacağını söylemez. Bu, önceki iki dersin ölçülerinin doğal bir
birleşimidir: bir kapanışın gövdesi çağrılana kadar koşmuyordu, bir dolaşım sözleşmesi
istenene kadar ilerlemiyordu — bu ders bu iki gözlemi birleştirip, "ne kadar istendiğinin"
zincirin ucundaki tek bir çağrıyla, tüketiciyle belirlendiğini gösteriyor. Aynı dört elemanlı kaynak ve aynı dönüşüm
gövdesiyle kurulan iki zincir, yalnızca uçları farklı olduğu için farklı sayıda koşabilir:
biri kaynağın tamamını isteyen bir toplama çağrısına bağlanır, öbürü ilk uygun değeri
bulunca duran bir arama çağrısına. Zincirin ortasındaki dönüşüm adımı, hangi tüketicinin
kendisini çağıracağını yazarken bilmiyor — bu bilgi yalnızca zincir tamamlanıp
çalıştırıldığında ortaya çıkıyor.

**YN8.** — "aynı dört elemanlı kaynaktan kurulan iki zincirin, ucuna toplama çağrısı
bağlanan gövdenin dört, ucuna ilk uygun değeri arayan çağrı bağlanan gövdenin iki kez
koştuğu" iddiası, aşağıdaki koşumla doğrulanıyor.

```rust
// tuketilen_ve_erken_biten.rs — kursun olcum cekirdegindeki kesit: zincirin kaynagi ayni, sonu farkli
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()));

    // tuketilen zincir: her elemanda
    let toplam: i32 = vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| {
            say(&defter, "tuketilen-zincir");
            x * 2
        })
        .sum();

    // erken biten zincir: yalniz gerektigi kadar
    let bulunan = vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| {
            say(&defter, "erken-biten-zincir");
            x * 2
        })
        .find(|x| *x > 2);

    println!(
        "tuketilen zincir govdesi kac kez kosti: {} (toplam {})",
        kere(&defter, "tuketilen-zincir"),
        toplam
    );
    println!(
        "erken biten zincir govdesi kac kez kosti: {} (bulunan {:?})",
        kere(&defter, "erken-biten-zincir"),
        bulunan
    );
}
```

```
tuketilen zincir govdesi kac kez kosti: 4 (toplam 20)
erken biten zincir govdesi kac kez kosti: 2 (bulunan Some(4))
```

İki zincirin ilk satırı birebir aynı yapıdadır: aynı dört elemanlı kaynak, aynı `x * 2`
dönüşümü. `.sum()` tüm kaynağı istiyor, bu yüzden dönüşüm gövdesi dört elemanın her biri
için bir kez koşuyor — kursun bağlayıcı tablosunda bu satır **her seferinde** sınıfına
düşüyor: tüketici kaynağın tamamını istediği sürece, gövde her elemanda kaçınılmaz olarak
çalışıyor. `.find(|x| *x > 2)` ise ilk uyan değeri arıyor: kaynak sırasıyla 2, 4, 6, 8
üretirken arama ikinci elemanda (`4 > 2`) duruyor, üçüncü ve dördüncü elemana hiç
uğranmıyor. Bu satır **yalnız gerektiğinde** sınıfına düşüyor — iki değil dört elemanın
tamamı üretilebilirdi, ama tüketici ikinci değerden sonra durmayı seçti; gövde yalnızca
tüketicinin sonucu istediği kadar koştu. Kaynağın uzunluğu ikisinde de dörttü; koşan gövde
sayısı ikisinde de farklı çıktı. 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 gövdenin
kaç kez koştuğudur.

Zincirin kaynak metnindeki tek fark tüketicinin adıdır — `sum` ya da `find`. Dönüşüm
gövdesinin kendisi, hangi tüketicinin onu çağıracağını bilmiyor ve bilmesi gerekmiyor:
sözleşmenin yöntemi ne kadar istenirse o kadar çalışıyor, kalanını hiç görmüyor. Zincire
üçüncü, dördüncü bir dönüşüm adımı eklense bile, bu ölçü değişmezdi — belirleyici olan
adım sayısı değil, tüketicinin kaç kez "bir sonrakini ver" dediği. Aynı dönüşüm gövdesi,
kaynak metninde hiç değişmeden, yalnızca zincirin ucundaki tek sözcük (`sum` yerine
`find`, `find` yerine başka bir arama ya da sayma çağrısı) değiştirilerek dört, iki, bir
ya da önceki derste görülen sıfır dahil sıfır ile dört arasında herhangi bir sayı
üretebilir.

**YN9.** — "aynı dönüşüm gövdesinin, ilk elemanın işlenmiş hâli aranan değere hemen
uyduğunda yalnızca bir kez koştuğu" iddiası, aşağıdaki koşumla doğrulanıyor.

```rust
// uc_tuketici.rs — ayni govde farkli bir tuketiciyle uculu farkli bir sayi verir
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()));

    let bulundu = vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| {
            say(&defter, "ilk-elemanda-duran-zincir");
            x * 2
        })
        .any(|x| x == 2);

    println!(
        "ilk elemanda duran zincir kac kez kosti: {} (bulundu mu: {})",
        kere(&defter, "ilk-elemanda-duran-zincir"),
        bulundu
    );
}
```

```
ilk elemanda duran zincir kac kez kosti: 1 (bulundu mu: true)
```

`.any(|x| x == 2)`, dönüştürülmüş ilk değerin (`1 * 2 = 2`) aranan değere zaten uyduğunu
görüp ikinci elemana hiç uğramadan duruyor. Aynı dönüşüm gövdesi bu üçüncü tüketiciyle bir
kez koştu — ne `tuketilen-zincir` ölçümündeki dört, ne `erken-biten-zincir` ölçümündeki
iki. Üç koşum bir arada — bir, iki, dört ve önceki dersten sıfır — aynı gövdenin
yalnızca tüketici değiştirilerek dört ayrı sayı üretebildiğini gösteriyor; sayı gövdenin
değil tüketicinin özelliğidir. Aranan değer ilk elemanda değil de son elemanda uysaydı,
`.any` da tıpkı `.find` gibi kaynağın tamamını dolaşırdı — durma noktası, tüketicinin
tanımından değil, aranan koşulun kaynakta nerede karşılandığından da etkileniyor.

## Zincirlenen Bağdaştırıcılar Eleman Başına Sırayla Koşuyor

İki dönüşüm adımı art arda zincirlendiğinde, akla gelen iki olası sıralama vardır: ya
birinci adım kaynağın tamamını işleyip bir ara sonuç üretir, sonra ikinci adım bu ara
sonucun tamamını işler (bağdaştırıcı başına toplu); ya da her eleman önce birinci adımdan,
hemen ardından ikinci adımdan geçer, sonra bir sonraki elemana geçilir (eleman başına
sırayla). Bu iki olasılık kaynak metinden ayırt edilemez — `.map(a).map(b)` yazımı
ikisiyle de tutarlı görünür; hangisinin gerçekleştiğini yalnızca koşum söyler.

Bir önceki bölümde kurulan sözleşme burada da geçerli: zincirin tek bir "bir sonrakini
ver" yöntemi var ve bu yöntem zincirin en dışındaki adımdan çağrıldığında, çağrı zincirin
içine doğru yayılıyor. En dıştaki adım kendi bir sonraki değerini istediğinde, bunun için
önce kendinden önceki adımdan bir değer istemesi gerekiyor; o adım da kendinden öncekinden
istiyor — zincir boyunca bu istek geriye doğru yayılıp bir kaynak değeriyle geri
dönüyor. Bu yayılma her seferinde tek bir eleman için oluyor, kaynağın tamamı için değil —
bu da ikinci olasılığı, eleman başına sırayı, işaret ediyor.

Her `map` çağrısı, kendi başına, kaynağın sözleşmesini gerçekleştiren yeni bir değer
üretiyor — bir yineleyiciyi sarıp aynı sözleşmeyi taşıyan başka bir yineleyici. İkinci
`map` çağrısı, birinci `map`in ürettiği bu yeni değeri kaynak olarak alıyor; kendisi de
aynı sözleşmeyi taşıyan üçüncü bir değer üretiyor. Zincirin en dışındaki tüketici bir
sonraki değeri istediğinde, aslında bu iç içe geçmiş üç sözleşmenin en dışındakini
çağırıyor; o da kendi kaynağından (ikinci `map`in ürettiği değer) bir sonrakini istiyor,
o da kendi kaynağından. Bu iç içe geçme, aşağıdaki koşumda tutulan kayıtla doğrudan
gözlemlenebiliyor.

**YN10.** — "iki bağdaştırıcı zincirlendiğinde, birinci adımın bir elemanı işlemesinin
hemen ardından ikinci adımın aynı elemanı işlediği, ikinci elemana geçmeden önce
tamamlandığı" iddiası, aşağıdaki koşumda tutulan sıra kaydıyla doğrulanıyor.

```rust
// bagdastirici_sirasi.rs — iki bagdastirici zincirlendiginde eleman basina sirayla kosuyor
use std::cell::RefCell;
use std::rc::Rc;

type Kayit = Rc<RefCell<Vec<String>>>;

fn kaydet(kayit: &Kayit, metin: String) {
    kayit.borrow_mut().push(metin);
}

fn main() {
    let kayit: Kayit = Rc::new(RefCell::new(Vec::new()));
    let kayit_a = Rc::clone(&kayit);
    let kayit_b = Rc::clone(&kayit);

    let sonuc: Vec<i32> = vec![1, 2, 3]
        .into_iter()
        .map(move |x| {
            kaydet(&kayit_a, format!("birinci-asama-{x}"));
            x + 1
        })
        .map(move |x| {
            kaydet(&kayit_b, format!("ikinci-asama-{x}"));
            x * 2
        })
        .collect();

    println!("sonuc: {:?}", sonuc);
    println!("sira: {}", kayit.borrow().join(", "));
}
```

```
sonuc: [4, 6, 8]
sira: birinci-asama-1, ikinci-asama-2, birinci-asama-2, ikinci-asama-3, birinci-asama-3, ikinci-asama-4
```

Kayıt sırası, bağdaştırıcı başına toplu değil eleman başına sırayla koştuğunu açıkça
gösteriyor: `birinci-asama-1` (birinci adımın ilk elemanı işlemesi) ile `ikinci-asama-2`
(ikinci adımın aynı sonucu hemen işlemesi) art arda geliyor, ikinci elemanın işlenmesi
üçüncü satırda başlıyor. Eğer koşum bağdaştırıcı başına toplu olsaydı, kayıt önce üç
`birinci-asama-*` satırı, sonra üç `ikinci-asama-*` satırı olarak gelirdi — koşum bunu
göstermiyor. Her eleman, zincirin başından sonuna kadar tek bir yolculuk yapıyor; bir
sonraki eleman bu yolculuk bitmeden başlamıyor.

Kayıt tutmak için burada `say`/`kere` çifti yerine paylaşımlı bir kayıt kabı (`Kayit`)
kullanıldı, çünkü bu ölçüm sayı değil sıra istiyor — kaç kez koştuğu değil, hangi
sırayla koştuğu önemli. İki dönüşüm kapanışı, aynı kayıt kabını `Rc::clone` ile ayrı ayrı
paylaşıyor; ikisi de aynı kaba yazabiliyor, çünkü kap kendi içinde değiştirilebilirliğini
taşıyor. Bu düzenek, Sahiplik ve Bellek Modeli kursunda kurulan paylaşımlı sahiplik
kurallarının burada da geçerli olduğunu gösteriyor — bu ders o kuralları yeniden kurmuyor,
yalnızca bir kayıt tutmak için kullanıyor.

Zincire üçüncü bir bağdaştırıcı eklense, aynı düzen sürerdi: her eleman üç adımdan da
sırayla geçer, dördüncü elemana geçmeden önce üçüncü adım da tamamlanırdı. Zincirin
uzunluğu sırayı değiştirmiyor, yalnızca her elemanın kaç durak yapacağını belirliyor.

Bu sıralama, ilk bölümde ölçülen erken durma davranışıyla da tutarlı: eğer zincirin
sonuna `.find` gibi erken duran bir tüketici bağlansaydı, üçüncü elemana hiç
ulaşılmadan zincir dururdu — ama ulaşılan her eleman yine de baştan sona, tüm adımlardan
sırayla geçerdi. Erken durma zincirin *kaç eleman* işlediğini sınırlıyor; eleman başına
sıralama ise işlenen *her bir* elemanın zincirde nasıl ilerlediğini belirliyor. İkisi
aynı sözleşmenin, "bir sonrakini ver" çağrısının, farklı iki sonucu.

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

İki bağdaştırıcının aynı elemanı art arda işlemesi, adımların birbirinden habersiz
olduğu anlamına gelmiyor — sıralama gözlemlenebilir olsa da, bu sıralamayı zincirin kaynak
metninden çıkarım yapıp tahmin etmek yerine bir kayıtla göstermek gerekti; kaynak metindeki
iki ardışık `map` çağrısının yazımı bu sırayı doğrudan söylemiyor. İkinci sınır, bu dersin
ilk ölçümünde görülen: iki zincirin dördü de kaynaktan üretilebilirdi, ama biri ikisinde
durdu. Bu durma kararı zincirin bir yerinde yazılı değil — tüketicinin kendi tanımında.
Aynı dönüşüm gövdesi, farklı bir tüketiciyle zincirlenseydi farklı bir sayı üretirdi; bu
ders o sayının zincirin kendisinden değil tüketiciden geldiğini gösterdi, ama her
tüketicinin ne zaman durduğunu genel bir kuralla vermiyor — her tüketici kendi durma
koşulunu taşıyor.

Üçüncü bir sınır, ölçüm aracının kendisiyle ilgili: her iki koşumda da dönüşüm gövdesine
bir kayıt çağrısı eklendi, ki bu çağrı olmasaydı gövdenin kaç kez koştuğu hiç
gözlemlenemezdi. Kayıt çağrısının kendisi ölçülen işin bir parçası değildir — dönüşümün
asıl işi `x * 2`dir, kayıt yalnızca bir gözlem aracıdır. Bu araç eklenince gövdenin kendi
maliyeti artmış olabilir, ama sayının kendisi (dört, iki) kayıt çağrısı olmasaydı da aynı
kalırdı; ölçüm, ölçtüğü şeyi değiştirmeden gözlemliyor.

Son bir sınır, bu konunun üç dersinin tümüne birden uzanır: ölçülen her sayı tek bir
koşumdan geldi. Kaynağın eleman sayısı, dönüşüm gövdesi ve tüketici sabit tutulduğu sürece
bu sayı koşumdan koşuma değişmiyor — kaynak dört elemanlı bir dizi olduğu, `map` içindeki
gövde `x * 2` olduğu ve `.find(|x| *x > 2)` her seferinde aynı sırayla sorguladığı sürece,
gövde her koşumda tam olarak iki kez koşacak. Bu belirlenimcilik, önceki konulardaki
ölçümlerin dayandığı aynı varsayımdır ve burada da bozulmuyor.

## Özet

- Aynı kaynak ve aynı dönüşüm gövdesiyle kurulan iki zincir, yalnızca uçlarındaki
  tüketiciye göre farklı sayıda koşabilir: biri **her seferinde** (dört elemanın hepsinde),
  öbürü **yalnız gerektiğinde** (ilk uyan bulununca durarak) koştu.
- Zincirin uzunluğu sabit kaldı (dört eleman); koşan gövde sayısı sabit kalmadı (dört, iki,
  bir) — belirleyici olan tüketicidir, zincirin kendisi değil.
- Dönüşüm gövdesi hangi tüketicinin onu çağıracağını bilmez; sözleşmenin yöntemi ne kadar
  istenirse o kadar çalışır.
- İki bağdaştırıcı zincirlendiğinde gövdeler bağdaştırıcı başına toplu değil, eleman
  başına sırayla koşuyor: bir eleman zincirin başından sonuna kadar tek bir yolculuk
  yapıyor, sonra bir sonraki eleman başlıyor.
- Bu sıralama kaynak metinden doğrudan okunmuyor; bir kayıtla gözlemlenmesi gerekiyor.
- Kayıt tutmak için kullanılan paylaşımlı kayıt kabı, Sahiplik ve Bellek Modeli kursunda
  kurulan paylaşımlı sahiplik kurallarının bir uygulamasıdır; bu kurallar burada yeniden
  kurulmadı, yalnızca bir gözlem aracı olarak kullanıldı.

## Sonraki Adım

Bu konuda bir kapanışın tek başına ne zaman koştuğu, bir dolaşım sözleşmesinin bu koşmayı
nasıl tek bir yönteme indirdiği ve bir zincirin ucundaki tüketicinin bu sayıyı nasıl
belirlediği ölçüldü. Üç ders birlikte, "kaynakta yazdığın bu gövde kaç kez koştu" sorusunu
giderek büyüyen birimlere uyguladı: tek bir kapanıştan, tek bir sözleşmeye, sözleşmeler
zincirine. Kursun kapanış dersi aynı soruyu somut bir veri biçimine taşıyor: bir yapının
alanlarına uygulanan bir dönüşüm gövdesi, yapı serilirken alan başına kaç kez koşuyor.
Orada zincirin elemanları artık bir dizinin girdileri değil, tek bir yapının alanları
olacak — eleman sayısı sabit ve küçük, tüketici tektir (serileştirmenin kendisi) — ama
sayan aynı soru: kaynakta yazılan bu gövde kaç kez koştu. Bu konuda öğrenilen ayrım orada
da geçerli kalacak: bir gövdenin kaynakta yazılı olması onun koştuğu anlamına gelmiyor,
kaç kez koştuğu da hep aynı sabit sayı olmak zorunda değil — belirleyici, gövdeyi kimin ve
ne zaman çağırdığıdır.
