---
title: Koleksiyonlar
source: 'https://academia.sh/tr/kurslar/rust-temelleri/koleksiyonlar'
course: 'Rust Temelleri'
language: tr
updated: '2026-09-13T05:09:28+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Büyüyen dizinin ekleme yönteminin deyim, çıkarma yönteminin ifade olduğunu gösterir'
    - 'Bir dizginin bayt sayısı ile karakter sayısının neden ayrıştığını ölçer'
    - 'Karma sözlüğün ekleme yönteminin bir ifade olduğunu ve eski değeri döndürdüğünü açıklar'
    - 'Yakalanmayan bir dönüş değerinin ne zaman sessiz veri kaybına yol açtığını örnekle gösterir'
---

# Koleksiyonlar

Aynı 'değiştirme' işi üç ayrı koleksiyonda ölçülüyor ama iki sınıftan birine düşüyor: büyüyen dizinin eklemesi () veriyor (deyim), karma sözlüğün eklemesi eski değeri Option olarak veriyor (ifade). Sınırlayıcı ölçüm bu dönüş değeri yakalanmazsa eski verinin sessizce kaybolduğunu gösteriyor.

Desen Eşleme dersi tek bir `Sekil` değerinin nasıl ayrıştırıldığını ölçtü; şimdiye kadarki
her ders tek bir değişkene bağlanan tek bir değeri konu etti. Ama bir programın verisi
neredeyse hiçbir zaman tek bir değerden ibaret değildir: birden çok alan aynı anda tutulur,
büyür, küçülür. Bu ders o sınırı kaldırıyor ve aynı soruyu — bir yazımın ifade mi deyim mi
olduğu — çok sayıda değeri bir arada tutan üç yapıya taşıyor: büyüyen dizi, dizgi, karma
sözlük.

Bu üç yapının ortak noktası, kendilerini **değiştiren** yöntemler taşımasıdır: bir öğe
eklemek, bir öğe çıkarmak. Bu dersin ölçtüğü soru şudur: aynı iş — "bir şey ekle" — üç
ayrı yapıda üç ayrı sınıfa mı düşüyor, yoksa hepsi aynı mı davranıyor? Ortak tanımın
çekirdeğinde bu soruya kısa bir yanıt zaten verilmişti: `HashSet::insert` hem kümeyi
değiştirip hem `bool` döndürüyordu, `Vec::push` ise yalnızca `()` veriyordu. Bu ders o tek
karşılaştırmayı üç yapıya, dört yönteme genişletiyor.

## Büyüyen Dizi: Ekleme Bir Deyim, Çıkarma Bir İfadedir

`Vec`, Rust'ın büyüyebilen dizi tipidir; sabit uzunluklu bir dizinin aksine, eleman sayısı
çalışma zamanında artıp azalabilir. İki temel değiştirici yöntemi vardır: sona bir öğe
eklemek ve sondan bir öğe çıkarmak. Bu iki yöntemin dönüş tipleri birbirinden tamamen
farklıdır — ve bu fark, bu dersin geri kalanında tekrar tekrar görülecek bir düzenin ilk
örneğidir: bir değiştirici yöntemin sınıfı, o yöntemin **ne işe yaradığından** değil,
**hangi tipi döndürdüğünden** okunur.

```rust
// buyuyen_dizi.rs — push () verir (deyim), pop Option verir (ifade)
fn main() {
    let mut alanlar: Vec<f64> = Vec::new();

    let itme_sonucu = alanlar.push(12.57); // Cember(2.0) alani
    println!("{:<24}: {:?}", "push donus degeri", itme_sonucu);

    alanlar.push(12.0); // Dikdortgen(3.0, 4.0) alani
    alanlar.push(6.0); // Ucgen(3.0, 4.0, 5.0) alani
    println!("{:<24}: {:?}", "alanlar (push sonrasi)", alanlar);

    let cikan = alanlar.pop();
    println!("{:<24}: {:?}", "pop donus degeri", cikan);
    println!("{:<24}: {:?}", "alanlar (pop sonrasi)", alanlar);
}
```

```
push donus degeri       : ()
alanlar (push sonrasi)  : [12.57, 12.0, 6.0]
pop donus degeri        : Some(6.0)
alanlar (pop sonrasi)   : [12.57, 12.0]
```

Sona ekleme yönteminin dönüş değeri `()`dir — çıktıda `push donus degeri: ()` bunu
gösteriyor. Bu bir **deyim**: `alanlar` değişir, ama bu değişimin sonucunu temsil eden bir
değer geri gelmez. Sondan çıkarma yöntemi ise `Option<f64>` döndürür — `Some(6.0)`, çünkü
listenin son öğesi `6.0`dı. Bu bir **ifade**: dönen değer, çıkarılan öğenin kendisidir ve
bir sonraki hesapta kullanılabilir.

**RV12.** — "Aynı iş sınıfındaki iki yöntem ayrı sınıflara düşebilir" iddiası burada
`push` ile `pop` çiftiyle ölçülüyor: ikisi de `alanlar` listesini değiştiriyor, ikisi de
tek bir öğeyle ilgileniyor, ama biri `()` biri `Option<f64>` veriyor. Bu ölçüm, ortak
tanımın çekirdeğinde (`ifade.rs`) `HashSet::insert` ile `Vec::push` arasında kurulan aynı
karşıtlığın bir yansımasıdır: sınıf, işin "ekleme" ya da "çıkarma" olmasından değil, o
işin dönüş tipinden okunur.

Neden bu fark var? Sona eklemek her zaman başarılıdır — listenin boş ya da dolu olması
sonucu değiştirmez, eklenecek yer her zaman vardır. Bu yüzden döndürülecek bilgilendirici
bir sonuç yoktur. Sondan çıkarmak ise her zaman başarılı olmayabilir: liste boşsa çıkarılacak
bir öğe yoktur. `Option`, bu iki olasılığı — bir öğe vardı (`Some`) ya da yoktu (`None`) —
tek bir dönüş tipinde taşır. `push`in "her zaman başarılı" olması onu bir sonuç döndürmekten
muaf kılarken, `pop`un "başarısız olabilmesi" onu bir sonuç döndürmeye zorluyor.

Çıktıdaki `alanlar (push sonrasi): [12.57, 12.0, 6.0]` satırı listenin tamamını gösteriyor;
köşeli parantezler ve virgüllerle ayrılan sayılar, `Vec`in kendi hata ayıklama (debug)
biçimidir. Üç `push` çağrısından sonra liste üç elemanlıdır; `pop` çağrısından sonra son
eleman (`6.0`) çıkarılır ve geriye iki eleman (`[12.57, 12.0]`) kalır. Listenin kaç eleman
tutabileceği ile ilgili bir üst sınır kaynakta hiçbir yerde yazılmıyor — `Vec` gerektiğinde
büyür, bu büyümenin gerçekleştirim ayrıntıları bu dersin konusu değil.

## Dizgi Bir Bayt Dizisidir

Rust'ta bir dizgi, karakterlerin değil **baytların** bir dizisidir; metin UTF-8 kodlamasıyla
tutulur ve her karakter aynı sayıda bayt kaplamaz. ASCII aralığındaki bir harf tek bir bayt
kaplarken, Türkçeye özgü `ç`, `ş`, `ğ`, `ı`, `ö`, `ü` gibi harfler iki bayt kaplar.

```rust
// dizgi_bayt_karakter.rs — dizgi bir bayt dizisidir, karakter sayisi ayri olculur
fn main() {
    let sekil_adi = "üçgen";
    println!("{:<24}: {}", "bayt sayisi (len)", sekil_adi.len());
    println!("{:<24}: {}", "karakter sayisi (chars)", sekil_adi.chars().count());
}
```

```
bayt sayisi (len)       : 7
karakter sayisi (chars) : 5
```

`"üçgen"` beş karakterden oluşur: `ü`, `ç`, `g`, `e`, `n`. Ama `len()` yöntemi (bayt
uzunluğunu veren) `7` sonucunu veriyor, `chars().count()` (karakter sayısını veren) ise
`5`. Aradaki iki baytlık fark, `ü` ve `ç` harflerinin her birinin UTF-8'de iki bayt
kaplamasından geliyor; `g`, `e`, `n` birer bayttır. Bu, önceki derslerde görülen "yalnızca
kaynağı okuyarak bulunabilen sayı" ile "yalnızca çalıştırarak bulunabilen sayı" ayrımının
bir başka örneğidir: `"üçgen"` yazımının kaç karakter olduğu kaynağı okuyarak sayılabilir,
ama kaç bayt tuttuğu, hangi harflerin çok baytlı olduğu bilinmeden kaynaktan çıkarılamaz.

**RV13.** — "Bayt sayısı ile karakter sayısının ayrıştığı" iddiası burada, iki farklı
yöntemin aynı dizgi üzerinde farklı sayı vermesiyle ölçülüyor: `len()` `7`, `chars().count()`
`5` veriyor. Fark tam olarak `2`dir ve bu, dizgideki iki çok baytlı karakterin (`ü`, `ç`)
her birinin bayt uzunluğuna bir fazladan katkısıyla açıklanır — beş karakterden ikisi
ikişer bayt, üçü birer bayt kaplıyor: `2×2 + 3×1 = 7`.

Bu ayrım, dizginin de bir koleksiyon olduğunu hatırlatıyor: `len()` yöntemi, `Vec`in
`len()`iyle aynı adı taşır ve aynı şeyi yapar — dizginin taşıdığı **öğe** sayısını verir.
Fark, bir dizginin öğelerinin bayt olmasıdır, karakter değil. `chars()` yöntemi bu baytları
gerçek karakterlere ayrıştırıp saymayı üstleniyor; bu ikinci bir geçiş gerektirir, çünkü
kaç baytın bir karakter oluşturduğu her karakterde değişebilir.

Bu yüzden bir dizgiye, bir büyüyen diziye erişir gibi konumla (`sekil_adi[0]` gibi) doğrudan
erişilemez. Bir büyüyen dizide konum `0`, her zaman bir tam öğedir; bir dizgide bayt konumu
`0`, çok baytlı bir karakterin **ortasına** denk gelebilir — `"üçgen"`in ilk baytı `ü`
harfinin tamamı değil, onun iki baytından yalnızca ilkidir. Konuma dayalı erişimin dizgiler
için tanımlanmamış olması, bu yarım karakter sorununu kaynaktan kaldırıyor: bir dizgiden
tek tek karakter almak isteyen kod, `chars()` üzerinden geçmek zorunda kalıyor ve bu geçiş
bayt sınırlarını değil karakter sınırlarını izliyor.

## Karma Sözlük: Ekleme Bir İfadedir

Karma sözlük (`HashMap`), anahtar-değer çiftlerini tutan bir koleksiyondur. Büyüyen dizi
bir öğeye konumla (`0`, `1`, `2`, …) erişirken, karma sözlük bir öğeye seçilen bir
anahtarla erişir — bir sayı, bir dizgi, karşılaştırılabilir herhangi bir tip. Bu ders
`&str` anahtarlar kullanıyor: her şekil adının kendi alan değerine karşılık geldiği küçük
bir tablo. Ekleme yöntemi, büyüyen dizininkinden farklı bir dönüş tipine sahiptir: `()`
değil, `Option<V>`.

```rust
// karma_sozluk_insert.rs — insert Option doner (ifade), dogrudan yazdirilmaz
use std::collections::HashMap;

fn main() {
    let mut alan_sozlugu: HashMap<&str, f64> = HashMap::new();

    let ilk_donus = alan_sozlugu.insert("cember", 12.57);
    println!("{:<24}: {:?}", "insert donus (ilk)", ilk_donus);

    alan_sozlugu.insert("dikdortgen", 12.0);
    alan_sozlugu.insert("ucgen", 6.0);

    let mut anahtarlar: Vec<&&str> = alan_sozlugu.keys().collect();
    anahtarlar.sort();
    for anahtar in anahtarlar {
        println!("{:<24}: {}", format!("alan_sozlugu[{}]", anahtar), alan_sozlugu[anahtar]);
    }
}
```

```
insert donus (ilk)      : None
alan_sozlugu[cember]    : 12.57
alan_sozlugu[dikdortgen]: 12
alan_sozlugu[ucgen]     : 6
```

`"cember"` anahtarı ilk kez eklendiğinde dönen değer `None`dur — bu anahtarın önceden bir
değeri yoktu. Bu, `Vec::push`in `()` vermesinden farklıdır: `insert`, eklemenin **öncesi**
hakkında bir bilgi taşıyan bir ifadedir. Eğer aynı anahtara ikinci kez ekleme yapılsaydı,
dönen değer `None` değil, önceki değeri taşıyan bir `Some` olurdu — bu, sınırlayıcı ölçümün
konusu.

Karma sözlüğün kendisi doğrudan yazdırılmıyor; anahtarlar önce bir listeye toplanıp
sıralanıyor, sonra tek tek erişiliyor. Bir karma yapının gezinme sırası koşumdan koşuma
değişebilir; bu derste basılan her sayının beş yıl sonra da aynı çıktıyı vermesi gerektiği
için, karma sözlüğün ham gezinme sırasına hiçbir yerde güvenilmiyor. Bu kuralın tam
gerekçesi ve karşıtı — sıralı sözlüğün gezinmesinin neden her koşumda aynı olduğu —
sıradaki dersin konusu.

Bu adım, `alan_sozlugu[anahtar]` erişiminin kendisini engellemiyor: bir anahtar zaten
biliniyorsa, o anahtarla değere ulaşmak doğrudan ve deterministiktir — değişen yalnızca
sözlüğün **tamamının** hangi sırayla dolaşılacağıdır. Bu yüzden yukarıdaki döngü önce
`keys()` ile bütün anahtarları alıyor, onları sıralıyor ve ancak sıralı listeyi
dolaşırken sözlüğe geri dönüp her anahtarın değerini okuyor — sözlüğün kendi iç sırasına
hiçbir noktada bakmadan.

**RV14.** — "insert'in bir ifade olduğu ve önceki değeri taşıdığı" iddiası burada ilk
ekleme çağrısının dönüş değeriyle ölçülüyor: `ilk_donus` adlı bir değişkene bağlanabiliyor
ve `{:?}` ile basılabiliyor — bir `()` için bu bağlama anlamsız olurdu, çünkü `()`in
taşıdığı hiçbir bilgi yoktur. `None` çıktısı, "cember" anahtarının bu sözlükte daha önce
hiç var olmadığını doğrudan söylüyor.

Anahtarları sıralamak için kullanılan `anahtarlar: Vec<&&str>` satırındaki çift `&`
işareti gelişigüzel değildir: `alan_sozlugu.keys()` yöntemi zaten sözlükteki anahtarlara
birer referans verir (`&str`) ve bu referansları bir listede toplamak listeyi
referansların referansı yapar (`&&str`). Bu ayrıntı, sözlüğün kendisini hiç kopyalamadan
yalnızca anahtarları okumaya izin verir; kopyalamanın ve referansların tam anlamı Sahiplik
ve Ödünç Alma dersinin konusudur, burada yalnızca sıralama adımının hangi tipte çalıştığı
görülüyor.

## Sınırlayıcı Ölçüm: Yakalanmayan Dönüş Değeri Sessizce Kaybolur

`insert`in döndürdüğü eski değer, bir değişkene bağlanmazsa program çalışmaya devam eder —
Rust bunu bir hata saymaz. Ama bu durumda eski değer, hiçbir yerde görünmeden kaybolur.

```rust
// insert_veri_kaybi.rs — insert'in eski degeri yakalanmazsa sessizce duser
use std::collections::HashMap;

fn main() {
    let mut stok: HashMap<&str, i32> = HashMap::new();
    stok.insert("cember", 5);
    stok.insert("cember", 9); // donus degeri yakalanmadi -- eski deger 5 burada kayboldu
    println!("{:<22}: {}", "yakalanmadan (guncel)", stok["cember"]);

    let eski_deger = stok.insert("cember", 3);
    println!("{:<22}: {:?}", "yakalanarak (eski)", eski_deger);
    println!("{:<22}: {}", "yakalanarak (guncel)", stok["cember"]);
}
```

```
yakalanmadan (guncel) : 9
yakalanarak (eski)    : Some(9)
yakalanarak (guncel)  : 3
```

İkinci satırda `"cember"` anahtarına `9` yazılıyor; bu satırın dönüş değeri (`5`i taşıyan
`Some(5)`) hiçbir değişkene bağlanmıyor, sonuç olarak hesaplanıp hemen atılıyor. Programın
geri kalanı bu kaybı fark etmez: `stok["cember"]` sorgusu doğrudan `9`u verir, çünkü sözlük
zaten güncellenmiştir. Kaybolan yalnızca **eski** değerdir — `5` sayısı, bu satırdan sonra
programın hiçbir yerinde yeniden elde edilemez.

Üçüncü çağrı aynı işlemi tekrarlıyor, ama bu kez dönüş değeri `eski_deger` adına
bağlanıyor. Sonuç `Some(9)`dur — bu, `stok["cember"]`in bu çağrıdan **önce** `9` olduğunu
söylüyor. Aynı satır hem sözlüğü günceller hem de güncellemeden önceki değeri geri verir;
tek fark, çağıranın bu değeri yakalayıp yakalamamasıdır.

**RV15.** — "Yakalanmayan dönüş değerinin veri kaybına yol açtığı" iddiası burada iki
farklı çağrı biçiminin yan yana koşturulmasıyla ölçülüyor: ikinci `insert` çağrısı (`9`
yazan) dönüş değerini atıyor ve `5`in programda bir daha görünmediği doğrudan gözlemleniyor;
üçüncü çağrı (`3` yazan) aynı yapıyı kullanıyor ama dönüş değerini `eski_deger`e bağlıyor
ve `Some(9)` olarak geri getiriyor. İki çağrı da aynı yöntemi, aynı imzayla çağırıyor;
fark yalnızca çağıranın sonucu bir ada bağlayıp bağlamadığında.

Bu, `insert`in bir ifade olmasının doğrudan bir sonucudur: bir ifadenin değeri her zaman
hesaplanır, ama bu değerin **kullanılması** zorunlu değildir. Bir deyimde böyle bir soru
hiç doğmaz — `push`in zaten döndürecek bir değeri yoktur, kaybedilecek bir şey de yoktur.
Kayıp riski, tam olarak dönüş değeri **taşıyan** yöntemlerde ortaya çıkar; bu risk, o
dönüş değerinin ne anlama geldiğini bilmeden kodu okuyan biri için görünmez kalabilir.

`stok` örneğindeki `"cember"` anahtarı bir sayım anlamı taşısaydı — örneğin depodaki
parça adedi — ikinci çağrının `5`i sessizce `9`a **değiştirmesi** (üzerine eklemesi değil)
gerçek bir veri kaybı olurdu: önceki adet hiçbir yerde toplanmadan kaybolurdu. Bu örnekte
`insert` bilerek "üzerine yaz" anlamında kullanıldı; bir önceki değeri toplama amacıyla
korumak isteyen bir kod, dönüş değerini mutlaka yakalamak zorundadır. Kaynakta bu iki
niyet — üzerine yazmak ve toplamak — aynı `insert` çağrısıyla ifade edilir; aradaki farkı
belirleyen, çağıranın dönüş değerini ne yaptığıdır.

Bu ders, üç ayrı koleksiyonun değiştirici yöntemlerini ölçtü ve hepsinin aynı iki
kalıptan birine düştüğünü gösterdi: bir yöntem ya `()` verir (deyim, `push` gibi) ya da
işlemin sonucuyla ilgili bir bilgi verir (ifade, `pop` ve `insert` gibi). Bu iki
koleksiyonun — büyüyen dizi ve karma sözlük — ortak noktası, ikisinin de "kaçıncı sırada"
ya da "hangi anahtarla" sorularına yanıt verse de, bu yanıtın **hangi sırayla** geleceği
konusunda aynı garantiyi vermemesidir. Büyüyen dizide sıra kaynaktaki ekleme sırasıdır ve
hiç değişmez. Karma sözlükte ise bu dersin ölçtüğü gibi, ham gezinme sırasına hiç
güvenilmedi — anahtarlar her zaman önce sıralandı.

## Özet

- Büyüyen dizinin sona ekleme yöntemi (`push`) `()` döner ve bir deyimdir; sondan çıkarma
  yöntemi (`pop`) `Option` döner ve bir ifadedir.
- Bir dizginin bayt uzunluğu ile karakter sayısı, çok baytlı karakterler içeren metinlerde
  birbirinden ayrışır.
- Karma sözlüğün ekleme yöntemi (`insert`) bir ifadedir; dönüş değeri, anahtarın önceki
  değerini (`Some`) ya da anahtarın yeni olduğunu (`None`) taşır.
- Karma sözlük doğrudan yazdırılmaz; anahtarlar önce toplanıp sıralanır.
- `insert`in dönüş değeri bir değişkene bağlanmazsa, üzerine yazılan eski değer sessizce
  kaybolur; bu risk yalnızca dönüş değeri taşıyan yöntemlerde vardır.

Bir koleksiyonun kendisi de aynı ifade/deyim/öğe ekseninden geçirilebilir: `Vec::new()` ve
`HashMap::new()` çağrıları birer ifadedir, çünkü boş bir koleksiyon değeri üretirler; bu
değeri `let` ile bir ada bağlamak da yine bir bağlama deyimidir. Bu dersin asıl katkısı,
koleksiyonun kendisinden değil, onu **değiştiren** yöntemlerden geliyor — çünkü değiştirme,
tek bir çağrının hem bir yan etki (koleksiyonun içeriği değişir) hem de isteğe bağlı bir
sonuç (dönüş değeri) taşıyabildiği tek an.

## Sonraki Adım

Bu ders, karma sözlüğün doğrudan yazdırılmadığını, anahtarların önce sıralandığını ölçtü
— ama bu neden gerekli ve karşıtı olan sıralı yapı bu sıralama adımına neden ihtiyaç
duymuyor? Sıradaki ders bu soruyu açıyor: sıralı sözlük ve sıralı küme ile karma sözlük ve
karma küme arasındaki güvence farkı nedir ve bu güvence hangi koşulu karşılamayı ister?
