---
title: 'Rust Temelleri'
source: 'https://academia.sh/tr/kurslar/rust-temelleri'
language: tr
updated: '2026-09-13T05:09:28+00:00'
license: 'CC BY-SA 4.0'
lessons: 12
outcomes:
    - 'Temel tipler, desen eşleme ve koleksiyonlarla program yazar'
    - 'Bir yazımın ifade mi deyim mi öğe mi olduğunu koşturarak ayırt eder'
    - 'Yapı ve numaralandırmalarla veri modelleyip desenle ayrıştırır'
    - 'Modül ve paket düzenini görünürlük kurallarıyla kurar'
---

# Rust Temelleri

Rust'ta bir kaynağı okurken en çok işe yarayan soru, satırın ne yaptığı değil ne ürettiğidir: kurs her düzeneği tek bir soruyla ölçer — bu yazılan şey bir değer mi üretiyor, yoksa yalnız iş mi yapıyor, yoksa yalnız bir ad mı bildiriyor? Değişkenler, temel tipler, denetim akışı, yapılar, numaralandırmalar, desen eşleme, koleksiyonlar ve modül düzeni aynı çerçeveden geçirilir.

## Dil Temelleri

Dilin tasarım hedeflerinin güvence ile maliyet arasındaki değiş tokuşa bağlanması, proje düzeninin bildirim dosyasıyla kurulması, değişmezliğin varsayılan olması ve gölgelemenin ona açtığı kapı, temel tiplerin taşıdığı değer aralıkları, bir gövdenin son satırının dönüş değeri olması, koşul ve döngü biçimlerinin değer üretip üretmemesi.

### Rust'ın Tasarım Hedefleri

Source: https://academia.sh/tr/kurslar/rust-temelleri/rustin-tasarim-hedefleri

On sekiz yazımlık bir ölçüm çekirdeği program içinden koşturulur ve her yazımı üç sınıftan birine yerleştirir — ifade, deyim, öğe; sonuç sekizi ifade, beşi deyim, beşi öğe olarak sabittir ve kursun geri kalanı bu üçlüyü tek soru olarak sürdürür: kaynakta yazılan bu şey bir değer mi üretiyor?

Go müfredatı beş kursla kapandı ve son kursu bir programın kendisi hakkında nelerin
bilinebileceğini ölçtü: bir bilgiyi kaynağın mı söylediğini, bir aracın mı, yoksa koşumun mu.
Bu müfredat aynı yöne bir adım daha yaklaşır ve doğrudan kaynağa bakar. Rust'ta bir satır
yazıldığında o satırın kaderi üçe ayrılır: satır **değerlendirilir ve bir değer üretir**,
**değerlendirilir ama hiçbir şey üretmez**, ya da **hiç değerlendirilmez, yalnız bir ad
bildirir**. Kurs boyunca sorulacak tek soru budur: kaynakta yazdığın bu şey bir değer mi
üretiyor?

Bu soru daha önce iki farklı biçimde soruldu. Java müfredatının ilk kursu derleyicinin
kaynağa neyi **eklediğini** ölçtü — kaynakta yazılı olmayan bir şeyin derleme sırasında nasıl
tamamlandığını. Go müfredatının ilk kursu ise bir şeyin **yazılmamasının** karşılığını ölçtü —
dilin bunu tanımlı mı bıraktığını, reddettiğini mi, yoksa açıkta mı bıraktığını. Bu kurs
ikisinden de ayrılır: burada eksik hiçbir şey yok, mesele kaynakta **yazılı olanın**
değerlendirilirken ne ürettiğidir.

Bu üçlü sınıflandırma bir tasarım hedefi olarak okunmalıdır, üç kategoriyi ezbere sıralayan
bir liste olarak değil: aynı işi kaynakta üç sınıftan hangisiyle yazdığın, o satırın nerede
kullanılabileceğini belirliyor. Bir ifadeyi bir değişkene bağlayabilir, bir işleve
geçirebilir ya da başka bir ifadenin içine gömebilirsin; bir deyim bunların hiçbirine uygun
değildir, çünkü elinde `()`ten başka bir şey yoktur. Kursun ilerleyen dersleri bu sınırın
nerede işe yaradığını — ve nerede bir yazım hatasına dönüştüğünü — tek tek gösterecek.

#### İfade, Deyim, Öğe

Üç yanıt vardır ve kurs boyunca bu üç ad değişmez.

| Sınıf | Tanım |
|---|---|
| ifade (expression) | Değerlendirilir ve `()` dışında bir değer üretir |
| deyim (statement) | Değerlendirilir ama `()` üretir — ya da hiç değerlendirilmez |
| öğe (item) | Yalnız bildirir; kendisi değerlendirilmez, değer **kullanınca** doğar |

Bu üçlünün ortasında görünen `()` bir boşluk değildir — Temel Tipler dersinde ayrıca ele
alınacak, ama şimdiden söylenmesi gereken şu: `()` de bir tiptir ve tek bir değeri vardır.
Bir deyim "hiçbir şey üretmiyor" değil, bu tek değerli tipin değerini üretiyor. `if`, `match`,
`loop` ve blok Rust'ta birer değerdir; noktalı virgül bir değeri **atar**; `fn`, `struct`,
`enum`, `mod` ve `const` ise hiç değerlendirilmez, yalnız derleyiciye bir ad tanıtır. Bu üç
yol var olduğu için soru burada bir kurs taşıyabiliyor.

Programlama Temelleri kursu (M01/K02) `if` yazımını Python'la kurdu; orada `if` bir deyimdi ve
bir değer üretmezdi. Bu kavram burada tekrar kurulmaz — tek cümlelik bu atıf, üç sınıfın neden
Rust'ta ayrı bir eksen oluşturduğunu göstermek içindir: aynı yazım her dilde aynı sınıfa
düşmüyor.

#### Ölçüm Çekirdeği

Kursun geri kalanında kullanılan çekirdek `ifade.rs`dir. On sekiz ayrı yazımı aynı çerçevede
koşturur, her birini bir **gözlem defterine** yazar ve sonunda sınıf başına toplamı basar.
Gözlem defterinin kendisi bir demet (tuple) dizisidir — her satır adı, sınıfı ve değeri üç
ayrı metin parçası olarak bir arada tutar. Demet, farklı tipteki birkaç değeri tek bir birim
gibi taşımanın en doğrudan yoludur; burada üç alanın da metin olması bir zorunluluk değil,
tablonun tek biçimde yazdırılabilmesi için yapılmış bir seçimdir. Gözlem defteri dilin bir
parçası değildir — kod okunurken buna dikkat edilmelidir.

**RD1.** `gozle` işlevi ve `defter` demeti (`String`, `String`, `String` üçlüsü) çekirdeğin
kendi tasarım kararıdır, Rust'ın bir düzeneği değildir. Bir yazımın hangi sınıfa girdiğine
karar veren şey her satırın **kaynaktaki biçimidir**; `gozle` çağrısı yalnız bu kararı bir
tabloya kaydeder ki on sekiz satır tek koşumda karşılaştırılabilsin.

```rust
// ifade.rs — kaynakta yazilan her sey uc siniftan birine girer:
// deger ureten (ifade), () ureten ya da hic degerlendirilmeyen (deyim),
// yalniz bildiren (oge).

use std::collections::BTreeMap;
use std::collections::HashSet;

const SINIR: i32 = 100;

struct Nokta {
    x: i32,
    y: i32,
}

enum Renk {
    Kirmizi,
    Yesil,
}

mod olcu {
    pub fn birim() -> i32 {
        3
    }
}

fn iki_kat(x: i32) -> i32 {
    x * 2
}

fn gozle(defter: &mut Vec<(String, String, String)>, ad: &str, sinif: &str, deger: String) {
    defter.push((ad.to_string(), sinif.to_string(), deger));
}

fn main() {
    let mut defter: Vec<(String, String, String)> = Vec::new();

    // --- ifade: deger ureten yazimlar ---

    let a = 7;
    let b = if a > 5 { "buyuk" } else { "kucuk" };
    gozle(&mut defter, "if bir deger olarak", "ifade", b.to_string());

    let renk = if a > 5 { Renk::Yesil } else { Renk::Kirmizi };
    let ad = match renk {
        Renk::Kirmizi => "kirmizi",
        Renk::Yesil => "yesil",
    };
    gozle(&mut defter, "match bir deger olarak", "ifade", ad.to_string());

    let blok = {
        let ic = iki_kat(a);
        ic + 1
    };
    gozle(&mut defter, "blok bir deger olarak", "ifade", blok.to_string());

    let mut sayac = 0;
    let dongu = loop {
        sayac += 1;
        if sayac == 4 {
            break sayac * 10;
        }
    };
    gozle(&mut defter, "loop break ile deger dondurur", "ifade", dongu.to_string());

    let n = Nokta { x: 1, y: 2 };
    gozle(&mut defter, "yapi soz dizimi bir deger uretir", "ifade", format!("x={} y={}", n.x, n.y));

    let v = vec![1, 2, 3, 4];
    gozle(&mut defter, "vec makrosu bir deger uretir", "ifade", format!("uzunluk={}", v.len()));

    let toplam: i32 = v.iter().map(|x| iki_kat(*x)).sum();
    gozle(&mut defter, "yineleyici zinciri bir deger uretir", "ifade", toplam.to_string());

    let mut kume: HashSet<i32> = HashSet::new();
    let ilk = kume.insert(5);
    let ikinci = kume.insert(5);
    gozle(&mut defter, "kume ekleme bir deger dondurur", "ifade", format!("{} sonra {}", ilk, ikinci));

    // --- deyim: () ureten ya da hic degerlendirilmeyen yazimlar ---

    let noktali = {
        iki_kat(2);
    };
    gozle(&mut defter, "noktali virgulle biten blok", "deyim", format!("{:?}", noktali));

    let mut d = 1;
    let atama = { d = d + 8; };
    gozle(&mut defter, "atamanin kendisi", "deyim", format!("{:?} (d={})", atama, d));

    let mut liste = Vec::new();
    let itme = liste.push(d);
    gozle(&mut defter, "diziye itme", "deyim", format!("{:?} (uzunluk={})", itme, liste.len()));

    let mut kez = 0;
    let dongu_degeri = for _ in 0..3 {
        kez += 1;
    };
    gozle(&mut defter, "for dongusu", "deyim", format!("{:?} (kez={})", dongu_degeri, kez));

    let yazim = print!("");
    gozle(&mut defter, "yazdirmanin degeri", "deyim", format!("{:?}", yazim));

    // --- oge: yalniz bildiren yazimlar; degerleri kullanildiklarinda dogar ---

    gozle(&mut defter, "fn bildirimi", "oge", format!("bildirim; cagrisi {} verdi", iki_kat(3)));
    gozle(&mut defter, "struct bildirimi", "oge", format!("bildirim; ornegi x={} verdi", n.x));
    gozle(&mut defter, "enum bildirimi", "oge", "bildirim; varyanti yesil verdi".to_string());
    gozle(&mut defter, "mod bildirimi", "oge", format!("bildirim; icindeki cagri {} verdi", olcu::birim()));
    gozle(&mut defter, "const bildirimi", "oge", format!("bildirim; okunmasi {} verdi", SINIR));

    // --- rapor ---

    println!("{:<40}{:<8}{}", "gozlem", "sinif", "deger");
    for (ad, sinif, deger) in &defter {
        println!("{:<40}{:<8}{}", ad, sinif, deger);
    }

    let mut sayim: BTreeMap<&str, i32> = BTreeMap::new();
    for (_, sinif, _) in &defter {
        *sayim.entry(sinif.as_str()).or_insert(0) += 1;
    }
    println!();
    for (sinif, adet) in &sayim {
        println!("{:<8}{}", sinif, adet);
    }
    println!("toplam  {}", defter.len());
}
```

```
gozlem                                  sinif   deger
if bir deger olarak                     ifade   buyuk
match bir deger olarak                  ifade   yesil
blok bir deger olarak                   ifade   15
loop break ile deger dondurur           ifade   40
yapi soz dizimi bir deger uretir        ifade   x=1 y=2
vec makrosu bir deger uretir            ifade   uzunluk=4
yineleyici zinciri bir deger uretir     ifade   20
kume ekleme bir deger dondurur          ifade   true sonra false
noktali virgulle biten blok             deyim   ()
atamanin kendisi                        deyim   () (d=9)
diziye itme                             deyim   () (uzunluk=1)
for dongusu                             deyim   () (kez=3)
yazdirmanin degeri                      deyim   ()
fn bildirimi                            oge     bildirim; cagrisi 6 verdi
struct bildirimi                        oge     bildirim; ornegi x=1 verdi
enum bildirimi                          oge     bildirim; varyanti yesil verdi
mod bildirimi                           oge     bildirim; icindeki cagri 3 verdi
const bildirimi                         oge     bildirim; okunmasi 100 verdi

deyim   5
ifade   8
oge     5
toplam  18
```

**RD2.** Koşum belirlenimcidir: aynı kaynak her koşumda aynı on sekiz satırı, aynı sırayla ve
aynı sınıf dağılımıyla üretir. Hiçbir satır bir dosya sisteminden, saatten ya da rastgele
üreteçten okumuyor — hepsi sabit bir kaynaktan hesaplanıyor. **On sekiz yazımın 8'i ifade,
5'i deyim, 5'i öğedir**; bu sayı kursun geri kalanında değişmez, yalnız her ders kendi
kesitini alır.

Sınıf başına toplamı hesaplayan son blok bir sıralı sözlük (`BTreeMap`) kullanıyor, karma
sözlük (`HashMap`) değil. Bu seçim rastgele değil: bir karma sözlüğün anahtarları arasında
gezinme sırası koşumdan koşuma değişebilir, üç sınıfın toplamı doğru çıksa bile satırların
**hangi sırayla** basılacağı garanti edilmez. Sıralı sözlük anahtarları her zaman aynı
sırada — burada alfabetik olarak deyim, ifade, öğe — dolaştığı için çıktı metni de
belirlenimci kalıyor. Bu, kursun ortama bağlı veri konusundaki kuralının en somut örneğidir:
bir koleksiyonun sırası bir gösterim aracı olarak kullanılacaksa, o sıranın güvence taşıyan
bir yapıdan gelmesi gerekir. Bu ayrım Sıralı ve Küme Yapıları dersinde kendi başına bir konu
olacak; burada yalnız çekirdeğin kendi çıktısını neden güvenle koşum sonrası koşuma
karşılaştırılabildiğini açıklıyor.

#### Sonuçların Okunuşu

Sekiz ifade satırının ortak noktası, hepsinin bir `let` bağlamasının sağ tarafında durup bir
değer üretmesidir: `if`/`match` bir dal seçer ve o dalın değerini verir, blok kendi son
satırını verir, `loop` yalnız `break`'e verdiği değeri verir, yapı sözdizimi ve `vec` makrosu
yeni bir değer kurar, yineleyici zinciri bir toplam biriktirir, küme ekleme ise `bool`
döndürür. Beş deyim satırı ise tam tersini gösteriyor: noktalı virgülle kapanan blok, bir
atama, `Vec::push`, `for` döngüsü ve boş bir yazdırma — beşi de `()` basıyor, çünkü beşi de
"bir iş yap" diyor, "bir değer ver" demiyor. Beş öğe satırı ayrı bir eksende duruyor: `fn`,
`struct`, `enum`, `mod` ve `const` bildirimlerinin kendisi tabloya hiç girmiyor, tabloya giren
şey bu bildirimlerin **kullanımından** doğan değer — `iki_kat(3)`'ün döndürdüğü `6`, `Nokta`
örneğinin alanı, `olcu::birim()`'in çağrısı, `SINIR`'ın okunması. Bir bildirim yazıldığı anda
hiçbir şey üretmiyor; yalnız bir ad tanıtıyor ve o ad ilerideki bir satırda kullanılınca değer
doğuyor.

**RD3.** `iki_kat` öğesi çekirdekte üç ayrı yerde kullanılıyor: bir kez `blok` içinde
(`ic + 1` hesabına girecek değeri üretmek için), bir kez yineleyici zincirinde her elemana
uygulanmak için, bir kez de "fn bildirimi" satırında doğrudan çağrılıp sonucu tabloya
yazılmak için. Üçünde de `iki_kat`'ın kendisi değişmiyor — değişen, her çağrıya verilen
argüman ve o çağrının döndürdüğü değer. Bu, öğenin "değersiz" olmasının ne anlama geldiğini
somutlaştırıyor: bildirim tek, ama kullanım sayısı ve her kullanımın ürettiği değer serbest.

Bu üç grup arasında sınıf sayısı eşit değildir ve eşit olması da beklenmiyor: kaynağın çoğu
bir değer üretmek için yazılıyor (8), geri kalanı ya bir yan etki için (5) ya da bir ad
tanıtmak için (5) yazılıyor. Kursun geri kalanı bu üç grubu tek tek derinleştirecek — `if`,
`match`, `loop` ve döngülerin tamamı Denetim Akışı dersinde, atama ve bağlama Değişkenler ve
Değişmezlik dersinde, bildirimlerin kaynak üzerindeki payı Kurulum ve Paket Yöneticisi
dersinde ayrıca ele alınacak. Bu derste kalan tek soru, sınıfın nereden okunduğudur.

#### Sınırlayıcı Ölçüm: Sınıf İmzadan Okunur

Tabloda yan yana duran iki satır bu sorunun yanıtını taşıyor: **"kume ekleme bir deger
dondurur"** (ifade, `true sonra false`) ile **"diziye itme"** (deyim, `() (uzunluk=1)`). İkisi
de aynı işi yapıyor gibi görünür — bir koleksiyona bir eleman eklemek. Ama biri koşumda bir
değer üretti, öbürü üretmedi. Fark, işin **doğasında** değil, çağrılan yöntemin **imzasında**
yatıyor.

`HashSet::insert` hem kümeyi değiştirir hem de eklemenin gerçekten yeni bir öğe kattığını
söyleyen bir mantıksal değer döndürür. Çekirdekte `5` iki kez eklenmiş: ilk çağrı kümeye yeni
bir öğe kattığı için `true`, ikinci çağrı zaten var olan `5`i tekrar eklemeye çalıştığı için
`false` döndürüyor — tablodaki `true sonra false` bu iki çağrının yan yana konmuş sonucudur.
`Vec::push` ise hiçbir zaman böyle bir bilgi vermiyor: bir diziye eleman eklemek her zaman
başarılı olduğu için döndürülecek bir mantıksal değer yok, imza yalnız `()` veriyor.

Bu, "ekleme" diye adlandırılan tek bir işin iki ayrı Rust yöntemine iki ayrı sınıf verdiğini
gösteriyor. Sınıfı belirleyen okuyucunun işin ne olduğuna dair sezgisi değil, derleyicinin
gördüğü dönüş tipidir: dönüş tipi `()` ise deyim, başka bir tip ise ifade. Bu ölçüt biçimsel
ve mekanik olduğu için, bir yöntemin çağrısına bakmadan, yalnız imzasına bakarak hangi sınıfa
gireceği önceden söylenebilir — `Option` ya da `bool` döndüren bir değiştirici her zaman
ifadedir, yalnız `()` döndüren bir değiştirici her zaman deyimdir. Koleksiyonlar dersinde bu
ayrım `Vec::pop`in `Option` döndürmesiyle bir kez daha karşımıza çıkacak.

Bu, kursun tasarım hedefi başlığı altında durmasının nedenini de açıklıyor: sınıf bir
çalışma zamanı gözlemi değil, bir **imza** kararıdır ve imza kaynakta koşum yapılmadan
okunabilir. Bir okuyucu `HashSet::insert`in dönüş tipine bakarak, hiçbir örneği koşturmadan,
onun bir ifade olduğunu söyleyebilir. Standart kitaplığın kendi tasarımı bu sınıflandırmayı
önceden belirliyor; ders boyunca ölçülen şey, bu belirlemenin kaynağı okurken nasıl bir
farkla karşımıza çıktığıdır.

#### Özet

- Kaynakta yazılan her şey üç sınıftan birine girer: ifade bir değer üretir, deyim `()`
  üretir ya da hiç değerlendirilmez, öğe yalnız bir ad bildirir ve değeri kullanımdan doğar.
- `()` boşluk değildir; tek değerli bir tiptir ve deyimin ürettiği şey budur.
- Ölçüm çekirdeği on sekiz yazımı tek koşumda sınıflandırır: 8'i ifade, 5'i deyim, 5'i öğe —
  bu sayı kursun geri kalanında değişmez.
- Aynı iş (ekleme) iki ayrı yönteme iki ayrı sınıf verebilir; sınıf işin doğasından değil,
  yöntemin dönüş tipinden — imzasından — okunur.

#### Sonraki Adım

Üç sınıf artık tanımlı, ama bir kaynağın gerçekten çalışabilmesi için bunlardan çok daha
küçük, çok daha zorunlu bir küme var: bir programın en az ne yazması gerekir. Sıradaki ders
bu en küçük kümeyi sorar — kaynağın kendisinde durmayan, ayrı bir dosyada tutulan bir parça
değişince kaynak hiç değişmeden çıktının nasıl değiştiğini gösterir.

### Kurulum ve Paket Yöneticisi

Source: https://academia.sh/tr/kurslar/rust-temelleri/kurulum-ve-paket-yoneticisi

Bir kaynağın çalışabilir bir ikiliye dönüşmesi için yazılması zorunlu üç parça vardır — giriş noktası, kaynak kökü, bildirim dosyası; üçü de öğedir, hiçbiri tek başına bir değer üretmez, ama üçü birlikte tek bir çıktı üretir ve bildirim dosyasındaki bir değişiklik kaynağa hiç dokunmadan o çıktının adını değiştirebilir.

Önceki ders üç sınıfı tanımladı ve on sekiz yazımı bu sınıflara ayırdı; hiçbiri tek başına
bir programın **çalışabilmesi** için yeterli değildi, çünkü sorulan soru zaten farklıydı.
Bu ders soruyu daraltıyor: bir kaynak metninin, hiçbir eksik olmadan, çalışan bir ikiliye
dönüşmesi için en az ne yazılmalı? Yanıt üç parçadır ve üçü de önceki dersten tanıdık bir
sınıfa giriyor — öğe. Hiçbiri kendi başına bir değer üretmiyor, ama üçü bir arada tek bir
çıktı üretiyor: çalıştırılabilir bir program.

Bu soru önceki dersteki sorudan küçük görünür ama bağımsız değildir. Önceki ders, kaynakta
yazılı olan bir şeyin değerlendirilirken ne ürettiğini sordu; bu ders ise değerlendirmenin
hiç başlayabilmesi için kaynağın etrafında **hangi çerçevenin** durması gerektiğini soruyor.
İfade, deyim ve öğe ayrımı yalnız Rust kaynağının içinde geçerli bir sınıflandırmadır; bu
ders o kaynağın nereden başladığını ve onu saran veriyle ilişkisini gösteriyor.

#### Üç Zorunlu Öğe

Bir kaynağın çalışabilir bir ikiliye dönüşmesi için gereken üç parça şunlardır: **giriş
noktası** (programın başlayacağı yeri işaretleyen `fn main`), **kaynak kökü** (derleyicinin
okumaya başladığı dosyanın kendisi) ve **bildirim dosyası** (paketin adını ve hangi dil
sürümüyle derleneceğini tutan veri dosyası). Standart bir proje düzeni bunu şöyle ayırır:

```text
proje/
├── Cargo.toml
└── src/
    └── main.rs

# Cargo.toml icerigi
[package]
name = "hesaplayici"
version = "0.1.0"
edition = "2021"
```

Bu üçü, önceki derste kurulan üç sınıftan **öğe**ye giriyor: hiçbiri tek başına
değerlendirilmiyor, yalnızca bir şey bildiriyor. `fn main`in kendisi bir işlev bildirimidir
— tıpkı önceki dersteki `iki_kat` gibi. Kaynak kökü bir dosyadır, dosyanın kendisi
"koşulmaz", yalnız içindeki bildirimler derleyiciye tanıtılır. Bildirim dosyası ise Rust
kaynağı bile değildir; TOML biçiminde bir veridir ve paket yöneticisi tarafından okunur.

Dizin ağacındaki ayrım gelişigüzel değildir: `src/` altında yalnız kaynak dosyaları durur,
`Cargo.toml` ise projenin köküne, `src/`ın dışına konur. Bu yerleşim, "kaynak" ile "kaynak
hakkındaki veri"yi aynı klasörde karıştırmama kararıdır — bir araç kaynak dosyalarının
tamamını taramak isterse yalnız `src/` dizinine bakması yeterlidir, bildirim dosyasını ayrı
bir mantıkla okur. Kaynak kökü konumuna gelince: burada tek dosyalık bir kaynak
kullanıyoruz ve onu doğrudan derleyiciye veriyoruz, çünkü bu kursta paket yöneticisi hiç
çalıştırılmıyor. Gerçek bir projede kaynak kökü `src/main.rs`dir ve derleyici oradan
başlayıp başka dosyalara `mod` bildirimleriyle ulaşır — bu genişleme Modüller ve Kasalar
dersinin konusu; burada yalnız kökün **tek bir dosya** olduğu ve derlemenin oradan
başladığı bilgisi yeterli.

**RD4.** `fn main`in "kullanılması" önceki dersteki bir işlevin kullanılmasından farklıdır:
`iki_kat` programın kendi içinden çağrılıyordu, `main` ise hiçbir satır tarafından
çağrılmıyor — onu çağıran, işletim sistemi sürecin başlangıcında derlenmiş ikiliyi
çalıştırdığında devreye giren çalışma zamanı ortamıdır. Bildirim (öğe) aynı bildirim, ama
çağıran taraf kaynağın dışında.

Bu, kaynağın kendi başına eksik olduğu anlamına gelmiyor; kaynak kaydı kaynak kökünde
tamamlanmış durumda, yalnız o kaydın **hangi anda** değere dönüşeceğine kaynak kendisi karar
veremiyor. Bir kaynakta `iki_kat`, `gozle` gibi başka öğeler de bulunabilir — hepsi bildirim
olarak durur, hiçbiri kendiliğinden koşmaz. Bunlardan yalnız biri, `main` adını taşıyan,
işletim sistemi tarafından tanınan giriş noktasıdır; diğerleri ancak `main`in gövdesinden ya
da `main`in çağırdığı başka bir öğeden ulaşılırsa değer üretir. Bu, önceki dersin "öğeler
ölçüde değersizdir" bulgusunun proje düzeyindeki karşılığıdır: bir kaynak ağacı istediği
kadar öğe bildirsin, giriş noktasından ulaşılamayan bir öğe hiçbir zaman koşmaz.

**RD5.** Bildirim dosyası hiç Rust kaynağı değildir, bu yüzden "ifade / deyim / öğe"
sınıflandırması ona gerçek anlamda uygulanmaz — o sınıflandırma yalnız Rust kaynağı için
tanımlıdır. Ama işlevsel olarak aynı yere düşüyor: bildirim dosyası da kendisi
"çalıştırılmıyor", yalnız paket yöneticisinin okuduğu bir veri sağlıyor ve nihai çıktıya
adıyla katkıda bulunuyor. Bildirim dosyasının biçimi de bu farkı görünür kılıyor:
`name = "hesaplayici"` bir anahtar-değer eşleşmesidir, bir çağrı ya da bir dallanma değil —
TOML'de değerlendirilecek bir kod yolu yok, yalnız okunacak bir veri var.

Bu üç parçanın birlikte oluşturduğu bütüne **paket** denir: bildirim dosyasının işaret
ettiği kaynak ağacı ile bildirim dosyasının kendisi, tek bir dağıtım ve derleme birimini
oluşturur. Paket yöneticisinin adı da buradan gelir — yönettiği şey tek bir kaynak dosyası
değil, kaynak ile kimliğin bir arada oluşturduğu bütündür. Bir paketin sınırı, dosya
sisteminde bildirim dosyasının bulunduğu dizindir; o dizinin altındaki her kaynak dosyası
aynı pakete ait sayılır.

TOML'ün kendisi de bu ayrımı destekleyecek biçimde tasarlanmış bir veri dilidir: yalnız
`anahtar = değer` satırları ve köşeli parantezle açılan bölüm başlıkları (`[package]` gibi)
içerir. Dallanma, döngü, fonksiyon çağrısı yoktur — bir bildirim dosyası okunurken
"çalıştırılacak" bir şey değil, dümdüz okunacak bir kayıt kümesidir. Bu, Rust kaynağının
kendisiyle taban tabana zıttır: kaynakta değerlendirilecek ifadeler ve deyimler vardır,
bildirim dosyasında yalnız veri vardır.

Kaynak kökü ile giriş noktası arasındaki fark da benzer bir ayrımdır ve karıştırılmamalıdır.
Kaynak kökü **bir dosyadır** (derleyicinin okumaya başladığı yer); giriş noktası ise o
dosyanın içindeki **belirli bir öğedir** (`fn main`, çalışmanın başlayacağı işlev). Küçük bir
programda ikisi aynı dosyada durabilir, ama kavramsal olarak ayrıdır: bir kaynak kökü, içinde
hiç `fn main` olmadan da başka dosyalara `mod` ile bağlanan yardımcı bildirimler taşıyabilir
— önceki derste bunu `mod olcu` ile gördük. Bir paketin çalıştırılabilir olması için gereken
şey kaynak kökünün kendisi değil, kaynak ağacının bir yerinde `fn main`in bulunmasıdır.

Bu ders boyunca gösterilen dizin ağacı ve bildirim dosyası metin bloğu çalıştırılmıyor ve
hiçbir sayı iddiası taşımıyor; yalnızca gerçek bir projenin nasıl göründüğünü belgeliyor.
Kursun geri kalanında koşan her örnek, paket yöneticisinden bağımsız, doğrudan derleyiciyle
çalışacak biçimde kurgulanacak — bu, ağ erişimi gerektirmeyen bir ölçüm ortamı kurmanın
sonucu, dilin kendisiyle ilgili bir kısıtlama değil.

Giriş noktasının tek başına ne yaptığını görmek için en küçük hâliyle koşturalım.

```rust
// programimiz.rs — bir kaynagin calisabilmesi icin en az yazilmasi gereken sey
fn main() {
    println!("dogrulama-anahtari={}", 7 * 6);
}
```

```
dogrulama-anahtari=42
```

Bu kaynakta tek bir öğe var: `fn main`. Kaynağın kendisi hiçbir değer üretmiyor —
derleyiciye "programın başlangıcı burası" diyor. Değer, program **koşturulduğunda** doğuyor,
tıpkı önceki dersteki `iki_kat(3)` çağrısının değeri fonksiyon **çağrıldığında**
doğurmasına benzer biçimde. Fark, çağıran tarafın kaynağın dışında olması.

Gövdenin içindeki yazdırma çağrısı kendisi önceki dersten tanıdık bir sınıfa giriyor: bir
deyim. Önceki dersin tablosunda "yazdırmanın değeri" satırı tam olarak bunu gösterdi —
yazdırma `()` döndürür, kendisi bir değer üretmez. Burada değişen tek şey, o deyimin artık
tek başına değil, `fn main` adlı bir öğenin gövdesinin içinde durmasıdır: öğe kendisi değer
üretmiyor, ama gövdesindeki deyim çalıştırıldığında bir yan etki (bir satırın ekrana
basılması) üretiyor. İfade, deyim ve öğe sınıfları böylece iç içe geçebiliyor — bir öğenin
gövdesi deyimlerden ve ifadelerden oluşabiliyor, ama öğenin kendisi hâlâ öğe kalıyor.

Kaynak kökünün derleyicinin okumaya başladığı tek dosya olması bir zorunluluktur: `fn main`
içermeyen bir dosya derlenip diske yazılabilir (önceki derste `mod` içindeki `olcu` işlevi
tam olarak bunu yaptı), ama işletim sisteminin doğrudan çalıştırabileceği bir ikili elde
etmek için bir yerde bir `fn main` bulunması şarttır. Bu, kursun geri kalanında tekrar
görülmeyecek tek bir olgudur: giriş noktası olmayan bir kaynak koleksiyonu derlenebilir,
ama çalıştırılabilir değildir.

Bu üç zorunlu parçanın birbirinden ayrılması bir rastlantı değil, kendisi bir tasarım
kararıdır — kursun başlığıyla aynı eksende durur. Kaynağı, kaynağın kimliğinden (ad, sürüm,
dil sürümü) ayırmak, ikisinin **bağımsız değişebilmesini** sağlıyor: bir projenin mantığı
hiç değişmeden adı değişebilir, ya da adı hiç değişmeden mantığı değişebilir. İki bilgiyi
aynı dosyada tutan bir tasarım bunu sağlayamazdı — kaynağı okuyan her araç, önce kimlik
bilgisini kaynağın neresinde arayacağını bilmek zorunda kalırdı.

#### Sınırlayıcı Ölçüm: Bildirim Dosyası Kaynağın İçinde Değildir

Bildirim dosyasının kaynaktan ayrı durmasının somut bir sonucu var: kaynağı hiç değiştirmeden,
yalnız bildirim dosyasındaki bir alanı değiştirerek çıktının **adını** değiştirebilirsin.
Paket yöneticisi normal bir projede ikilinin adını bildirim dosyasının `name` alanından
türetir. Aynı ilkeyi, paket yöneticisi çalıştırmadan, doğrudan derleyicinin çıktı adlandırma
seçeneğiyle gösterelim — kaynak (`programimiz.rs`) hiç değişmiyor, yalnız hedef ad değişiyor.

```bash
isim_a="hesaplayici"
isim_b="hesap-araci"
rustc --edition 2021 -o "$isim_a" programimiz.rs
rustc --edition 2021 -o "$isim_b" programimiz.rs
echo "cikti_a: $(./$isim_a)"
echo "cikti_b: $(./$isim_b)"
if [ "$isim_a" != "$isim_b" ]; then
  echo "ikili_adlari_farkli: evet"
else
  echo "ikili_adlari_farkli: hayir"
fi
```

```
cikti_a: dogrulama-anahtari=42
cikti_b: dogrulama-anahtari=42
ikili_adlari_farkli: evet
```

**RD6.** Bu ölçüm paket yöneticisini çalıştırmıyor — bu derste de hiçbir kod bloğunda
koşturulmuyor. Gösterilen şey, paket yöneticisinin ikili adını bir veri alanından türetme
**ilkesidir**: `rustc`in `-o` seçeneği burada bildirim dosyasındaki `name` alanının yerini
tutuyor. Aynı kaynak dosyası iki kez, iki farklı hedef adla derlendi ve ikisi de birebir aynı
çıktıyı verdi; değişen tek şey ikilinin adı oldu.

Bu sonuç, önceki dersin "sınıf imzadan okunur" bulgusuyla aynı ailededir: orada bir
yöntemin sınıfı çağrı yerine değil imzasına bakılarak belirleniyordu, burada bir ikilinin
adı kaynağa değil bildirim dosyasına bakılarak belirleniyor. İki durumda da kaynağın kendisi
bir bilgiyi taşımıyor; o bilgi kaynağın **dışında** bir yerde duruyor ve kaynak o bilgiden
habersiz çalışıyor. `programimiz.rs` dosyası "hesaplayici" ya da "hesap-araci" adında bir
ikiliye dönüşeceğini hiçbir satırında bilmiyor.

Ölçümdeki `cikti_a` ve `cikti_b` satırlarının birebir aynı olması da kendi başına bir
gözlemdir: aynı kaynak, aynı derleyici seçenekleriyle iki kez derlendiğinde iki ayrı ikili
üretiyor ama davranışları hiç ayrışmıyor. Bu, önceki dersteki belirlenimcilik bulgusunun
derleme düzeyindeki karşılığıdır — orada aynı kaynağın her koşumda aynı on sekiz satırı
ürettiği gösterilmişti, burada aynı kaynağın her derlemede aynı davranışı ürettiği
gösteriliyor. Değişen tek şey, derlemenin dışına bırakılan bir isimdir.

Bu bağımsızlık tek yönlü değil. Derleme tamamlandıktan sonra üretilen ikili, kaynaktan da
bağımsızlaşır — kaynak dosyası silinse bile, daha önce üretilmiş ikili çalışmaya devam eder.

```bash
rustc --edition 2021 -o ikiliornek programimiz.rs
mv programimiz.rs programimiz_yedek.rs
echo "calisma: $(./ikiliornek)"
if [ -f programimiz.rs ]; then
  echo "kaynak_hala_ayni_adda: evet"
else
  echo "kaynak_hala_ayni_adda: hayir"
fi
```

```
calisma: dogrulama-anahtari=42
kaynak_hala_ayni_adda: hayir
```

**RD7.** İkili, derlemenin **sonucudur**; kaynağın kendisi değil, kaynağın belirli bir anda
değerlendirilmiş hâlidir. Kaynak dosyası taşınsa ya da silinse bile ikili bunu bilmez, çünkü
bağ derleme anında kurulmuş ve o andan sonra ikili kendi başına bir dosyadır. Bu, giriş
noktası – kaynak kökü – bildirim dosyası üçlüsünün nihai amacını gösteriyor: üçü bir arada,
kendi kendine yeten, kaynaktan bağımsız tek bir çıktı üretiyor. Bu, dağıtım pratiğinde sık
karşılaşılan bir durumun temelidir: bir sunucuya yalnız derlenmiş ikili taşınır, kaynak hiç
oraya gitmez — ikili kendi başına çalışabildiği için bu taşımanın hiçbir sakıncası yoktur.

Bu ayrımın somut bir pratik değeri var: aynı hesaplama mantığını taşıyan bir kaynak dosyası,
bir bağlamda iç bir araç olarak "hesaplayici" adıyla, başka bir bağlamda dağıtılan bir
paketin parçası olarak bambaşka bir adla derlenebilir. Kaynak hiç kopyalanıp
değiştirilmeden, yalnız çevresindeki bildirim değiştirilerek iki ayrı kimlik elde edilir —
yukarıdaki ölçüm bunu birebir gösteriyor: `programimiz.rs` bir kez bile açılıp
düzenlenmeden iki farklı adla derlendi.

Bu ayrımın pratik bir sonucu var: bir projenin adını değiştirmek, kaynak metninde tek bir
karakter değiştirmeden yapılabilecek bir işlemdir. Kaynak kökü ile bildirim dosyası aynı
projenin iki ayrı görünürlük katmanını taşıyor — biri **ne çalıştığını**, öbürü **projenin
nasıl adlandığını ve hangi dil sürümüyle derleneceğini** söylüyor. Bu iki katman birbirine
karışmıyor: bildirim dosyasını okumadan kaynağı okuyabilir, kaynağı okumadan bildirim
dosyasını okuyabilirsin ve ikisi de öbürü hakkında hiçbir varsayımda bulunmuyor.

Aynı ayrım tersinden de geçerlidir: aynı kaynak kökü, iki ayrı bildirim dosyasıyla iki ayrı
projenin parçası olabilir. Bir kaynak dosyasının hangi projeye ait olduğunu belirleyen şey
dosyanın içeriği değil, onu hangi bildirim dosyasının işaret ettiğidir. Bu, `programimiz.rs`
örneğinde görüldüğü gibi, kaynağın taşınabilirliğinin bir sonucudur: dosyanın içeriği sabit
kalırken çevresindeki bildirim değişebiliyor ve bu iki değişim birbirinden bağımsız.

Bildirim dosyasının taşıdığı diğer alanlar da (yukarıdaki örnekte görülen sürüm ve dil
sürümü satırları) aynı ilkeye uyuyor: kod bloğunda durur, kaynağın kendisine hiç
karışmıyor. Derleyiciye bu derste doğrudan `--edition 2021` seçeneği verildi çünkü paket
yöneticisi hiç koşturulmuyor; gerçek bir projede bu bilgiyi paket yöneticisi bildirim
dosyasından okuyup derleyiciye kendisi iletir. Kaynak dosyası bu bilgilerin hiçbirini
taşımaz — yalnız **ne yaptığını** bilir, çevresindeki bildirimin neyi taşıdığını bilmez.

Bu ders, önceki dersteki "öğe" sınıfının yalnız tek bir bildirim satırıyla sınırlı
olmadığını gösterdi. Bir dosyanın kendisi (kaynak kökü) ve bir projenin kimliği (bildirim
dosyası) da aynı mantıkla okunabiliyor: ikisi de kendi başına bir değer üretmiyor, ikisi de
yalnız bir çerçeve kuruyor ve o çerçevenin içinde çalışan kod bir çıktı üretiyor. Sıradaki
ders bu çerçevenin **içine**, giriş noktasının gövdesine iniyor ve orada ilk yazılan
satırların çoğunun bir ada bir değer bağlamak olduğunu ele alıyor.

#### Özet

- Bir kaynağın çalışabilir bir ikiliye dönüşmesi için üç parça zorunludur: giriş noktası,
  kaynak kökü, bildirim dosyası.
- Üçü de öğedir: hiçbiri kendisi bir değer üretmez, üçü birlikte tek bir çıktı — çalışan bir
  program — üretir.
- Giriş noktasını "kullanan" taraf kaynağın kendisi değil, işletim sisteminin süreç
  başlatma anıdır.
- Bildirim dosyası Rust kaynağı değildir ve kaynağın dışında durur; kaynağı hiç değiştirmeden
  yalnız bildirim dosyasını değiştirerek çıktının adı değiştirilebilir.
- Kaynak kökü ile bildirim dosyası birbirinden habersiz iki ayrı katmandır: biri neyin
  çalıştığını, öbürü projenin nasıl adlandığını taşır.
- Derlenmiş ikili, üretildikten sonra kaynaktan bağımsızlaşır: kaynak dosyası silinse ya da
  taşınsa bile, önceden üretilmiş ikili çalışmaya devam eder.

#### Sonraki Adım

Giriş noktasının içinde artık bir gövde yazılabilir, ama o gövdenin ilk satırı genellikle bir
ad kurmaktır — bir değeri bir adla bağlamak. Sıradaki ders bu bağlamanın kendisinin hangi
sınıfa girdiğini sorar ve aynı adın üç kez yeniden bağlanmasıyla bir kez bağlanıp iki kez
değiştirilmesi arasındaki farkı, ikisi de aynı sonucu verse bile, koşturarak gösterir.

### Değişkenler ve Değişmezlik

Source: https://academia.sh/tr/kurslar/rust-temelleri/degiskenler-ve-degismezlik

let bir bağlama deyimidir ve atamanın kendisi () üretir; aynı adın üç kez yeniden bağlanması (gölgeleme) ile bir kez bağlanıp iki kez değiştirilmesi (mut) aynı sayısal sonuca ulaşır, ama yalnız gölgeleme aradan tip değiştirebilir — çünkü biri her seferinde yeni bir bağlama kurar, öbürü var olan bağlamanın üzerine yazar.

Giriş noktasının gövdesine artık inilebilir ve gövdenin ilk satırlarının çoğu bir ada bir
değer bağlar (binding). Bu ders bağlamanın kendisini iki açıdan ölçüyor: bağlama işleminin
kendisi bir ifade mi deyim mi ve aynı adı yeniden bağlamanın Rust'ta iki ayrı yolu — biri
her seferinde yepyeni bir bağlama kuran gölgeleme, öbürü var olan bağlamanın üzerine yazan
`mut` — neden aynı sonuca ulaşırken birbirinden bu kadar farklı davranıyor.

Programlama Temelleri kursu (M01/K02) değişken tanımını Python'la kurdu ve gölgelemeyi de
orada tanımladı. Bu kavramlar burada tekrar kurulmaz; bu dersin payı, Rust'ın bağlamayı
**varsayılan olarak değişmez (immutable)** kurması ve gölgelemeye bu değişmezliğin
içinden bir kapı açmasıdır.

Bu sıralama gelişigüzel değil. Önceki ders bir kaynağın çalışabilmesi için gereken en küçük
kümeyi kurdu; bu ders o kümenin içine, giriş noktasının gövdesine iniyor ve orada bir adın
bir değere nasıl bağlandığını soruyor. Sıradaki ders bu bağlanan değerin **hangi tipte**
olabileceğini soracak — ama bir tipin ne olduğunu sormadan önce, bir adın o tipteki değere
nasıl tutunduğunu ve bu tutunmanın ne kadar sıkı olduğunu bilmek gerekiyor. Değişmezlik
işte bu sıkılığın adıdır.

#### Bağlama Bir Deyimdir

`let ad = deger;` yazımı iki ayrı parçaya ayrılır. Eşittir işaretinin sağı bir ifadedir —
değerlendirilir ve bir değer üretir. Bütün satır, yani `let` ile başlayan bağlamanın kendisi,
bir deyimdir: hiçbir yerde bir değer olarak kullanılamaz. Bu ayrım küçük görünse de
sonuçları somuttur — bir bağlamayı bir işleve argüman olarak geçiremez, bir listeye
ekleyemez, başka bir ifadenin içine gömemezsin, çünkü elinde `()`ten başka bir şey yoktur.

**RD8.** Rust'ta `let` yalnız gövde düzeyinde durur ve bir ifadenin içine yerleştirilemez;
`(let x = 5)` gibi bir yazım derleyici tarafından kabul edilmez. Bu, `let`in "her zaman bir
deyim" olmasının somut karşılığıdır — istisnası yoktur, hiçbir bağlamda bir değere
dönüşmez. Bunun bir sonucu, kaynağı okuyan tarafın yeni bir adın nerede kurulduğunu tek bir
yerden takip edebilmesidir: her yeni bağlama bir satırın başında, `let` ile açılır; bir
ifadenin ortasında gizlenmiş bir bağlama arama gerekmez.

Atamanın kendisinin de aynı sınıfa girdiğini önceki derste `ifade.rs` çekirdeğinde gördük
("atamanın kendisi" satırı `()` bastı). Burada aynı olguyu, değişkenler konusuna özgü küçük
bir örnekle tekrar koşturalım.

```rust
// deyim_olarak_atama.rs — atamanin kendisi bir deger uretmez
fn main() {
    let mut x = 1;
    println!("x baslangicta: {}", x);
    let atama_sonucu = { x = 9; };
    println!("x simdi: {}", x);
    println!("atamanin kendi degeri: {:?}", atama_sonucu);
}
```

```
x baslangicta: 1
x simdi: 9
atamanin kendi degeri: ()
```

`x = 9` bir ifade olarak değerlendiriliyor — `x`in yeni değeri belleğe yazılıyor — ama bu
ifadenin **kendi değeri** `()`. `atama_sonucu` adlı bağlama bu `()`i tutuyor, `9`u değil.
`x`in yeni değerine ulaşmanın tek yolu `x`in kendisini okumaktır; atamanın sonucunu okumak
hiçbir zaman işe yaramaz, çünkü orada okunacak bir değer yok.

Bu, önceki dersteki bir gözlemi tamamlıyor: `if`, `match`, `loop` ve blok birer değerdir,
ama `let` ve atama birer değer değildir. Aynı dilde hem "bu bir değerdir" hem "bu bir değer
değildir" diyen iki grup yazımın bir arada durması bilinçli bir tercihtir. Bir dallanma ya
da bir döngünün değer üretmesi, o yazımın sonucunun doğrudan bir bağlamaya aktarılmasını
sağlıyor; bir bağlamanın kendisinin değer üretmesi ise anlamsız olurdu, çünkü bağlama zaten
kendisi bir sonuç değil, bir sonucu **saklama** işlemidir. Değer üretmek ile bir yer ayırıp
oraya yazmak, kaynakta iki ayrı eylem olarak kalıyor ve sınıflandırma bu ikisini
karıştırmıyor.

#### Gölgeleme ve `mut`: Aynı Sonuç, İki Farklı Yol

Aynı adı yeniden bağlamanın Rust'ta iki yolu var. Biri **gölgeleme (shadowing)**: `let`
anahtar sözcüğü tekrar yazılır ve yepyeni bir bağlama kurulur; eski bağlama artık o adla
erişilemez ama yok olmamıştır. Öbürü `mut`: bağlama bir kez `let mut` ile kurulur, sonraki
satırlar `=` ile doğrudan üzerine yazar; burada yeni bir bağlama yok, var olan bağlamanın
tuttuğu değer değişiyor. İkisini yan yana koşturarak aynı iki adımı (üç ekle, iki ile
çarp) uygulayalım.

```rust
// baglama.rs — golgeleme ile mut arasindaki fark
fn main() {
    // golgeleme: ayni ad uc kez baglaniyor, her biri yeni bir baglama
    let deger = 5;
    let deger = deger + 3;
    let deger = deger * 2;
    println!("golgeleme sonucu: {}", deger);

    // mut: bir kez baglaniyor, iki kez degistiriliyor (ayni baglamaya yazma)
    let mut sayac = 5;
    sayac = sayac + 3;
    sayac = sayac * 2;
    println!("mut sonucu: {}", sayac);

    println!("esit mi: {}", deger == sayac);
}
```

```
golgeleme sonucu: 16
mut sonucu: 16
esit mi: true
```

İki yol da `16`ya ulaşıyor, ama vardıkları yer aynı olsa da oraya gidiş biçimleri farklı.
Gölgelemede üç ayrı `deger` bağlaması var — ikincisi birinciyi okuyup yeni bir bağlama
kuruyor, üçüncüsü ikinciyi okuyup bir yenisini daha kuruyor. `mut` tarafında ise tek bir
`sayac` bağlaması var; iki atama satırı da aynı bağlamanın üzerine yazıyor, yeni bir bağlama
kurmuyor.

Bu iki yolu ayırt eden soru şudur: bir sonraki satır, önceki satırın kurduğu adı mı
**okuyor**, yoksa önceki satırın kurduğu yere mi **yazıyor**? Gölgelemede her `let deger`
satırı önce sağdaki ifadeyi (bir önceki `deger`i kullanarak) değerlendiriyor, sonra bu
sonucu tamamen yeni bir bağlamaya yerleştiriyor — okuma ve yeni bağlama kurma iki ayrı
adımdır. `mut` tarafında okuma ve yazma aynı bağlama üzerinde gerçekleşiyor; `sayac = sayac
+ 3` satırı önce `sayac`ın o anki değerini okuyor, sonra aynı bağlamaya yeni değeri
yazıyor. Sonuç ikisinde de bir toplama ve bir çarpmadır, ama biri adı üç kez yeniden
kullanırken öbürü aynı adı hiç bırakmıyor.

**RD9.** Gölgelemede eski bağlama "silinmiyor", yalnız adıyla erişilemez hâle geliyor. İlk
`deger` (`5`) ile ikinci `deger` (`8`) hâlâ bellekte bir yerde bulunabilir, ama kaynakta
onlara ulaşacak bir ad kalmadı — üçüncü `let deger` ile o ad son bağlamaya taşındı. Bu
davranış K02'nin konusu olan bellek yönetimiyle ilgilidir; burada yalnız gözlemlenen şudur:
gölgeleme adı yeniden kullanıyor, bağlamayı değil.

Gölgelemenin adı yeniden kullanması, önceki dersteki bir başka olguyla birleşiyor: blok
kendisi bir ifadedir ve kendi kapsamını taşır. Bir bloğun içindeki gölgeleme, blok
kapandığında etkisini kaybediyor.

```rust
// golgeleme_kapsam.rs — golgeleme kapsam icinde kalir
fn main() {
    let deger = 10;
    let iceride = {
        let deger = deger * 100;
        deger
    };
    println!("blok icindeki golgeleme: {}", iceride);
    println!("disaridaki deger degismedi: {}", deger);
}
```

```
blok icindeki golgeleme: 1000
disaridaki deger degismedi: 10
```

İç bloktaki `let deger = deger * 100;` dış `deger`i okuyup kendi kapsamında yeni bir
bağlama kuruyor; bu yeni bağlama yalnız bloğun içinde geçerli. Blok kapandığında dış
`deger` hiç dokunulmamış hâliyle geri geliyor — iç bağlama dış bağlamanın üzerine hiçbir
zaman yazmadı, yalnız aynı adı kendi dar kapsamında ödünç aldı. Bu, gölgelemenin `mut`tan
ayrıldığı ikinci nokta: `mut` ile yapılan bir değişiklik kapsam sınırı tanımaz, aynı
bağlamanın olduğu her yerde görünür; gölgeleme ise her `let` ile hem yeni bir bağlama hem de
o bağlamanın kapsamını yeniden kurar.

#### Gölgelemenin Tip Değiştirebilmesi

Bu iki yol arasındaki fark yalnız mekanik değil, yetenek farkıdır da. Gölgeleme her seferinde
yepyeni bir bağlama kurduğu için, yeni bağlamanın tipi eskisiyle aynı olmak zorunda değildir.

```rust
// golgeleme_tip.rs — golgeleme ayni adin tipini degistirebilir
fn main() {
    let deger = 21;
    let deger = deger * 2;
    let deger = format!("sonuc={}", deger);
    println!("{}", deger);
}
```

```
sonuc=42
```

İlk `deger` bir tam sayı, üçüncü `deger` bir dizgi (`String`). Üçü de aynı adı taşıyor ama
üçü de birbirinden bağımsız bağlamalar; sonuncusu öncekinin tipini bilmek zorunda değil,
yalnız değerini okuyor ve yeni bir tipte yeni bir bağlama kuruyor.

`mut` ile aynı yazım denenirse derleyici reddeder: `let mut deger = 21` satırından sonra
`deger`e bir dizgi biçimlendirme çağrısının sonucunu atamaya çalışan bir satır derlenmez,
çünkü `mut` yeni bir bağlama kurmuyor, var olan bağlamanın **aynı tipteki** başka bir
değerle değiştirilmesine izin veriyor. Bağlama bir
kez `i32` olarak kurulduktan sonra, o bağlamaya bir `String` yazılamaz — derleyici için bu,
farklı boyuttaki iki değeri aynı yere sığdırmaya çalışmakla eşdeğerdir. Gölgeleme bu kısıtı
taşımıyor, çünkü her `let` derleyiciye "burada yeni bir yer ayır" diyor; `mut` ise "var olan
yere yaz" diyor ve o yerin biçimi ilk `let` ile sabitleniyor.

Bu fark, gölgelemenin neden yalnız bir kısayol olmadığını gösteriyor. Aynı adı taşıyan bir
dizi dönüşüm zincirinde (bir dizgiyi ayrıştırıp bir sayıya, sonra o sayıyı biçimlendirilmiş
bir dizgiye çevirmek gibi) her adımın kendi doğal tipinde kalmasına izin veriyor; okuyan
taraf her adımda hangi tipte olduğunu bağlamanın en son `let` satırından okuyor, ara
adımların tipini takip etmek zorunda kalmıyor. `golgeleme_tip.rs` örneğinde bu zincir üç
adımlıydı: tam sayı olarak başladı, tam sayı olarak katlandı, dizgi olarak biçimlendi. `mut`
ile aynı zincir yazılmak istenseydi, ya üç ayrı ad gerekirdi (`ham_deger`, `katlanmis_deger`,
`bicimli_deger`), ya da her adımın aynı tipte kalması için ekstra bir dönüştürme adımı
eklemek gerekirdi. Gölgeleme bu iki seçeneği de gereksiz kılıyor: tek bir ad, dönüşümün
mantıksal adımlarını izliyor, ama her adımın kendi tipini taşımasına izin veriyor.

Bu yeteneğin bir bedeli de var: aynı adın art arda kaç kez gölgelendiğini takip etmek,
okuyan taraf için `mut`a göre daha fazla dikkat gerektirir. `mut` bir bağlamanın tipini asla
değiştirmediği için, kodun ortasında `sayac`ı gördüğünde tipin ne olduğu ilk `let mut`tan
bellidir. Gölgelemede ise aynı garantiyi vermek için en yakın `let deger` satırına kadar
geriye gitmek gerekir — üç satır önceki `deger` başka bir tip taşıyor olabilir. Kursun
geri kalanında gölgeleme genellikle kısa, birbirine yakın satırlar arasında kullanılacak;
bu yakınlık, tip takibinin okuma sırasında kaybolmamasını sağlıyor.

#### Sınırlayıcı Ölçüm: Değişmezlik Bağlamanın Sınırındadır

Önceki iki bölüm değişmezliği hep **tek bir değer** üzerinden gösterdi — bir tam sayı ya
da bir dizgi. Değişmezliğin, birden çok bileşeni bir arada tutan bir değer üzerinde nasıl
davrandığını netleştirmek gerekiyor. `mut` yazılmadan kurulan bir bağlama
yalnız kendi değerini değil, değerin **bütün iç alanlarını** da korur — bir demedin (tuple)
tek bir bileşenini bile ayrıca değiştiremezsin.

```rust
// degismezlik_siniri.rs — baglama degismezken ic alanin durumu
fn main() {
    let nokta = (3, 4);
    println!("baslangic: ({}, {})", nokta.0, nokta.1);

    let nokta2 = (nokta.0 + 1, nokta.1);
    println!("yeni baglama: ({}, {})", nokta2.0, nokta2.1);
    println!("eski baglama degismedi: ({}, {})", nokta.0, nokta.1);
}
```

```
baslangic: (3, 4)
yeni baglama: (4, 4)
eski baglama degismedi: (3, 4)
```

`nokta` hiç `mut` almadan kuruldu. Onu "güncellemek" isteseydik `nokta.0 = 4;` yazmak
gerekirdi — bu satır derlenmez, çünkü `nokta` değişmez bir bağlamadır ve bu değişmezlik
demedin her bileşenine birden uygulanır, yalnız dışarıdan görünen ada değil. Bunun yerine
kod yeni bir bağlama (`nokta2`) kurdu ve eskisinin bileşenlerinden ikisini okuyup üçüncü bir
değeri hesapladı; `nokta` çıktının son satırında görüldüğü gibi hiç değişmedi. Yeni bağlama eskisinin
üzerine değil, eskisinin **yanına** kuruldu; iki bağlama aynı anda, birbirinden bağımsız
olarak var olmaya devam ediyor.

**RD10.** Bu, "değişmezlik derindir" gibi okunabilir ama tam resim değildir. Burada
gösterilen şey, **bir bağlamanın kendisinin** değişmez olduğu — o bağlamaya ait hiçbir
bileşen `mut` olmadan yeniden yazılamaz. Ama aynı verinin **başka bir bağlama ya da
referans üzerinden** paylaşılıp paylaşılamayacağı, paylaşılırsa değişmezliğin oradan da
geçerli olup olmayacağı — bu, sahiplik ve ödünç alma kurallarının sorusudur ve K02'nin
konusudur. Burada çizilen sınır şu: bir bağlamanın `mut` almaması, o bağlamanın kendi adı
üzerinden hiçbir değişikliğe izin vermeyeceğini garanti eder; verinin tamamı hakkında daha
geniş bir garanti değildir.

Bu sınır, önceki iki dersteki sınırlayıcı ölçümlerle aynı ailededir. Rust'ın Tasarım
Hedefleri dersinde bir yöntemin sınıfı çağrı yerine değil imzasına bakılarak belirleniyordu;
Kurulum ve Paket Yöneticisi dersinde bir ikilinin adı kaynağa değil bildirim dosyasına
bakılarak belirleniyordu. Burada da benzer bir kalıp var: bir bağlamanın "ne kadar
değişmez" olduğu, yalnız o bağlamanın kendi bildirimine (`mut` var mı yok mu) bakılarak
belirleniyor — verinin başka yerlerde nasıl paylaşıldığına bakılmadan. Üç ders de aynı
dersi tekrarlıyor: Rust'ta bir garanti okurken, garantinin **nereden** geldiğini bilmek,
garantinin kendisi kadar önemli.

#### Özet

- `let ad = deger;` bir deyimdir ve hiçbir yerde bir değer olarak kullanılamaz; sağ taraftaki
  ifade değerlendirilip ada bağlanır.
- Bir atamanın kendisi de `()` üretir; yeni değere ulaşmanın tek yolu adı okumaktır.
- Gölgeleme her `let` ile yepyeni bir bağlama kurar; `mut` ile yeniden atama var olan
  bağlamanın üzerine yazar. İkisi de aynı sayısal sonuca ulaşabilir.
- Yalnız gölgeleme bağlamanın tipini değiştirebilir, çünkü her adımda yeni bir yer ayrılır;
  `mut` bağlamanın ilk tipine bağlı kalır.
- Bir bağlamanın değişmez olması, o bağlamanın bütün iç bileşenlerini kapsar, ama verinin
  başka bir yoldan paylaşılıp paylaşılamayacağı sorusuna yanıt vermez.
- Gölgeleme kapsamla sınırlıdır: bir blok içindeki gölgeleme, blok kapandığında dış
  bağlamayı hiç etkilemeden kaybolur; `mut` ile yapılan değişiklik kapsam tanımaz.

#### Sonraki Adım

Bağlamaların taşıdığı değerlerin kendisi henüz tek tek incelenmedi — yalnız tam sayılar
görüldü. Sıradaki ders Rust'ın temel tiplerine iner: tam sayı, kayan noktalı, mantıksal,
karakter ve demet ve her birinin bir ifade olarak ürettiği değerin ne olduğunu, `()`in de
neden bu tiplerden biri sayıldığını koşturarak gösterir. Bu derste kurulan bağlama kavramı
orada değişmeyecek — yalnız bağlanan değerlerin çeşidi genişleyecek ve her tipin kendi
sınırları (bir tam sayının taşabileceği aralık, bir demedin sabit uzunluğu gibi) tek tek
ölçülecek.

### Temel Tipler

Source: https://academia.sh/tr/kurslar/rust-temelleri/temel-tipler

Tam sayı, kayan noktalı, mantıksal, karakter ve demet — beş temel tip, birer ifade olarak koşturulduğunda beş ayrı değer üretir; ama altıncı bir tip daha vardır — (), tek bir değeri olan tip — ve bir deyimin ürettiği şeyin yokluk değil, tam olarak bu tipin o tek değeri olduğu, aynı koşumda iki değer yan yana basılarak gösterilir.

Önceki ders bağlamanın kendisini ele aldı ama bağlanan değerlerin çeşidine girmedi — yalnız
tam sayılar görüldü. Bu ders o boşluğu dolduruyor: Rust'ın beş temel tipi (tam sayı, kayan
noktalı, mantıksal, karakter, demet) birer ifade olarak koşturulduğunda ne üretiyor ve bu
beşin yanında duran altıncı bir tip — `()` — neden "değersiz" değil, tam tersine kendi
başına bir tip.

Beş temel tipin her biri, önceki dersteki değişmezlik tartışmasının üzerine kurulan sabit
bir sınır taşır. Bir tam sayı belirli bir bit genişliğine sahiptir ve bu genişlik alabileceği
en büyük ve en küçük değerleri belirler; bir kayan noktalı sayı yaklaşık bir hassasiyet
taşır; bir mantıksal değer yalnız iki durumdan birini alabilir; bir karakter tek bir Unicode
kod noktasını temsil eder; bir demet sabit sayıda bileşenden oluşur ve bu sayı derleme
zamanında bellidir. Bu sınırların her biri bu derste ayrı ayrı ölçülüyor.

#### Beş Tip, Beş Değer

Aşağıdaki kaynak beş temel tipten birer değer bağlıyor ve her birini yazdırıyor; ardından
demedin bileşenlerini **yapısöküm (destructuring)** ile ayrı adlara ayırıyor.

```rust
// temel_tipler.rs — her temel tipin bir ifade olarak urettigi deger
fn main() {
    let tam: i32 = -7;
    let kayan: f64 = 2.5;
    let mantiksal: bool = kayan > 2.0;
    let harf: char = 'r';
    let ikili: (i32, bool) = (tam, mantiksal);

    println!("tam sayi: {}", tam);
    println!("kayan noktali: {}", kayan);
    println!("mantiksal: {}", mantiksal);
    println!("karakter: {}", harf);
    println!("demet: ({}, {})", ikili.0, ikili.1);

    let (ilk, ikinci) = ikili;
    println!("yapisokum ilk: {}", ilk);
    println!("yapisokum ikinci: {}", ikinci);

    let birim: () = ();
    let mut sayac = 0;
    let deyim_sonucu = { sayac += 1; };
    println!("acikca tipi olan birim: {:?}", birim);
    println!("bir deyimin urettigi: {:?}", deyim_sonucu);
    println!("ikisi ayni deger mi: {}", birim == deyim_sonucu);
    println!("sayac su an: {}", sayac);
}
```

```
tam sayi: -7
kayan noktali: 2.5
mantiksal: true
karakter: r
demet: (-7, true)
yapisokum ilk: -7
yapisokum ikinci: true
acikca tipi olan birim: ()
bir deyimin urettigi: ()
ikisi ayni deger mi: true
sayac su an: 1
```

İlk beş yazdırma satırı, önceki dersteki "ifade bir değer üretir" tanımının beş ayrı tip
üzerinden tekrarıdır: `-7` bir tam sayı değeridir, `2.5` bir kayan noktalı değerdir, `kayan >
2.0` bir mantıksal değer üretir, `'r'` tek bir karakterdir, `(tam, mantiksal)` iki değeri bir
arada tutan bir demettir. `mantiksal`ın kendisi de dikkat çekiyor: onu üreten şey bir sabit
değil, bir karşılaştırma ifadesidir — Rust'ta karşılaştırma işleçlerinin kendisi de birer
ifadedir ve `bool` tipinde bir değer döndürür.

Bu beş değerin tip açıklamaları (`i32`, `f64`, `bool`, `char`, `(i32, bool)`) burada
bilerek açıkça yazıldı; Rust bunları çoğu zaman sağ taraftaki değerden çıkarabilir, ama
tipin kendisi kaynakta yazılmasa bile hep vardır — her bağlamanın tek bir sabit tipi olur ve
bu tip derleme zamanında belirlenir. `tam` değişkeni `-7` değerini taşıyor ve tipi `i32`;
Rust'ın varsayılan tam sayı tipi budur, otuz iki bit genişliğinde ve hem negatif hem pozitif
değer taşıyabilir. `kayan` değişkeni ise `f64` tipinde, altmış dört bit genişliğinde bir
kayan noktalı sayıdır ve Rust'ın varsayılan kayan noktalı tipidir. Demedin tipi
`(i32, bool)` biçiminde yazılıyor — parantez içinde, virgülle ayrılmış, bileşenlerin kendi
tipleri sırayla. Bir demedin tipi yalnız bileşen tipleriyle değil, bileşen **sayısıyla** da
belirlenir: iki elemanlı bir demet ile üç elemanlı bir demet, bileşenleri aynı olsa bile
farklı tiplerdir.

**RD11.** `let (ilk, ikinci) = ikili;` satırı, önceki bölümde görülen `ikili.0` /
`ikili.1` biçiminden farklı bir erişim yolu kullanıyor: demedin bileşenlerini teker teker
okumak yerine, demedin **biçimini** bir desende tekrarlayıp iki yeni adı tek satırda
bağlıyor. Bu, sağdaki `ikili` ifadesinin değerlendirilip demedin sol taraftaki desenle
eşleştirilmesiyle çalışıyor; sol taraf bir demet biçimindeyse, sağ taraf da aynı sayıda
bileşene sahip bir demet olmak zorunda. Desen eşlemenin daha genel biçimi ileride ayrıca
ele alınacak; burada yalnız demede özgü bu tek biçim kullanıldı.

Demedin sabit bileşen sayısı, önceki derste `Vec` benzeri büyüyebilen bir yapıdan farklı bir
garanti veriyor: `ikili` iki bileşenli olarak kurulduğu andan itibaren, kaynağın hiçbir
yerinde üçüncü bir bileşen eklenemez ya da birinci bileşen çıkarılamaz. Bu sabitlik derleme
zamanında bilinir ve yapısöküm satırının solundaki desenin sağdaki demetle **birebir**
sayıca eşleşmesini zorunlu kılar — `let (ilk, ikinci, ucuncu) = ikili;` gibi bir yazım,
`ikili` yalnız iki bileşen taşıdığı için derlenmez. Bu, bir demedin tipinin yalnız
bileşenlerin tipleriyle değil sayısıyla da tanımlandığının bir başka görünümü.

#### Sınırlayıcı Ölçüm: `()` Değersiz Değil, Tek Değerli

Çıktının son dört satırı bu dersin asıl iddiasını taşıyor. `birim` adlı bağlama açıkça `()`
tipinde tanımlandı ve `()` değeriyle bağlandı — bu, `()`in gerçek bir tip olduğunu, tıpkı
`i32` ya da `bool` gibi bir tip adı taşıdığını gösteriyor. `deyim_sonucu` ise bambaşka bir
yoldan geldi: bir blok içinde `sayac`ı bir artıran bir deyimin sonucu olarak. İki değer
farklı yollardan üretildi, ama eşitlik sınaması `true` verdi — çünkü `()` tipinin **tek bir
değeri** var ve her iki bağlama da o tek değeri tutuyor.

Bu, "bir deyim değer üretmez" cümlesinin yanlış anlaşılabileceği yeri gösteriyor. Deyim
değer üret**mez** demek yanıltıcı olurdu; doğrusu, deyim `()` tipinin tek değerini üretir.
Yokluk ile "tek değerli bir tipin değeri" aynı şey değildir: yokluk bir tipin bile olmaması
demektir, oysa `()` gerçek bir tiptir, boyutu tanımlıdır ve fonksiyon imzalarında dönüş
tipi olarak açıkça yazılabilir — nitekim önceki ölçüm çekirdeğindeki `iki_kat` gibi bir
işlev `-> i32` yazarken, gövdesi yalnız bir yan etki üreten bir işlev hiçbir dönüş tipi
yazmaz, çünkü varsayılan dönüş tipi zaten `()`tir.

`f64` bu altı tip arasında kendine özgü bir sınır taşıyor: taşıdığı değer sayısı sonlu olsa
da, gerçek sayılar sonsuz olduğu için her ondalık değer tam karşılığını bulamıyor — `2.5`
gibi bazı değerler tam temsil edilirken, bazı basit kesirler yaklaşık bir değerle temsil
ediliyor. Bu ders bu yaklaşıklığı ayrıca ölçmüyor; burada yalnız `kayan`ın kendisinin bir
ifade olarak nasıl bir değer ürettiği gösterildi, hassasiyetin sınırları kendi başına ayrı
bir konudur.

Diğer beş tipin her biri birden çok değer alabiliyor — bir `i32` milyarlarca farklı değerden
biri olabilir, bir `bool` en azından ikisinden. `()` bu düzenden ayrılıyor: alabileceği değer
sayısı tam olarak bir. Bu, `()`i diğer beş tipten "daha az" yapmıyor, yalnız **farklı**
yapıyor — bir tipin taşıdığı bilgi miktarı, o tipin kaç ayrı değer alabileceğiyle ölçülürse,
`()` sıfır bilgi taşıyor demektir ve bu da tam olarak bir deyimin iletmek istediği şeydir:
"bu satır çalıştı" bilgisinin kendisi, hangi değerin üretildiğinden bağımsız.

Altı tipi taşıdıkları değer sayısına göre bir sıraya koyarsak, `()` bir uçta durur (bir
değer), `bool` onun hemen yanında (iki değer), sonra `char` (yaklaşık bir milyon
Unicode kod noktası kadar), sonra `i32` ve `f64` (milyarlarca değer) gelir; demedin kendi
değer sayısı, bileşenlerinin değer sayılarının çarpımıdır. Bu sıralama rastgele değil: bir
tipin taşıyabileceği bilgi miktarı doğrudan bu sayıyla ilişkilidir ve `()`in en uçta
durması, bir deyimin neden "bilgi taşımayan bir sonuç" olarak tanımlandığını gösteriyor.

Bu okuma, `()`in neden `bool`dan farklı olduğunu da açıklıyor. `bool` iki değer taşıdığı için
bir "evet/hayır" bilgisini kodlayabiliyor; `()` tek değer taşıdığı için hiçbir ayrım
kodlayamıyor — üretildiğini bilmek, hangi seçeneğin gerçekleştiğini bilmekle aynı şey değil,
çünkü seçenek tek. Bir yöntemin dönüş tipi `()` ise, o yöntemin çağrısının **başarılı
olduğunu** bilirsin (aksi hâlde program çökerdi ya da derleyici reddederdi), ama çağrının
hangi durumu ürettiğini bilemezsin — bu, önceki dersteki `Vec::push` örneğiyle aynı
noktadır: `push` bir eleman eklendiğini garanti eder, ama eklemenin "nasıl" gittiğine dair
hiçbir ek bilgi vermez.

#### Tam Sayı Taşması: Tanımlı Bir Davranış

Tam sayı tipleri sabit bir bit genişliğine sahiptir ve bu genişliği aşan bir toplam
**taşar (overflow)**. Rust bu durumu tanımsız bırakmaz; taşmanın ne olacağını açıkça
seçmeni ister. Sarma (`wrapping_add`) yöntemi bu seçimlerden biridir: sonucu, tipin
alabileceği en büyük değerin bir fazlasını en küçük değere döndürerek hesaplar.

```rust
// tasma_ve_karakter.rs — tasmanin tanimli davranisi ve karakterin bayt olmamasi
fn main() {
    let en_buyuk: u8 = u8::MAX;
    let tasmis = en_buyuk.wrapping_add(1);
    println!("en buyuk u8: {}", en_buyuk);
    println!("tasma sonrasi: {}", tasmis);

    let ascii_kelime = "agac";
    let ozel_kelime = "ağaç";
    println!("agac bayt: {} karakter: {}", ascii_kelime.len(), ascii_kelime.chars().count());
    println!("ağaç bayt: {} karakter: {}", ozel_kelime.len(), ozel_kelime.chars().count());
}
```

```
en buyuk u8: 255
tasma sonrasi: 0
agac bayt: 4 karakter: 4
ağaç bayt: 6 karakter: 4
```

`u8` sekiz bitlik bir tam sayı tipidir ve alabileceği en büyük değer `255`tir. `255`e `1`
eklemek normal toplamada tipin sınırını aşar; `wrapping_add` bu aşımı **tanımlı** bir kurala
bağlıyor — sonucu tipin aralığına "sarıyor" ve `0`a dönüyor. Bu, taşmanın rastgele bir
davranışa yol açmadığını gösteriyor: `wrapping_add` her koşumda, her makinede aynı yanıtı
verir, çünkü kural bit genişliğinin kendisinden geliyor, çalışma zamanının o anki durumundan
değil.

Bu davranış rastgele seçilmiş bir örnek değil, gerçek bir ihtiyacın karşılığıdır: döngüsel
olarak sayılıp belirli bir sınırda başa dönmesi beklenen bir değer — bir hafta içindeki gün
sırası, dairesel bir arabellekteki konum — tam olarak sarma davranışına ihtiyaç duyar.
`wrapping_add` bu ihtiyacı tek bir çağrıyla karşılıyor ve sonuç, taşmanın **hangi kurala**
göre ele alınacağını kaynağın kendisinde görünür kılıyor. Standart kitaplık aynı ailede başka
yöntemler de sunuyor — taşmayı bir hata olarak bildiren ve taşmayı tipin sınırında durduran
yöntemler gibi; her biri aynı soruna farklı bir tanımlı yanıt veriyor, ama hiçbiri tanımsız
bırakmıyor.

**RD12.** Bir tam sayı tipinin bit genişliği (`u8` için sekiz bit, `i32` için otuz iki bit)
dilin kendisinde sabittir ve makineye göre değişmez — bu, işaretçi genişliğine bağlı olan
`usize` gibi tiplerden farklıdır. `wrapping_add`in her koşumda aynı sonucu vermesinin nedeni
tam olarak budur: ölçülen şey donanıma değil, tipin kendi tanımına ait bir sınır.

#### Karakter Bir Bayt Değildir

Aynı kaynağın ikinci yarısı iki kelimenin uzunluğunu iki farklı biçimde ölçüyor. `len()`
dizginin **bayt** cinsinden uzunluğunu veriyor, `chars().count()` ise dizginin kaç
**karakter** içerdiğini sayıyor. `"agac"` dizgisinde bu ikisi eşit çıkıyor — dört bayt, dört
karakter — ama `"ağaç"` dizgisinde ayrışıyor: altı bayt, dört karakter.

Bunun nedeni Rust'ın dizgileri UTF-8 ile kodlamasıdır — İngilizce alfabesindeki harfler tek
bir baytla temsil edilirken, `ğ` ve `ç` gibi harfler iki bayt gerektiriyor. `char` tipi
kendisi tek bir Unicode kod noktasını temsil ediyor, dizgideki bir baytı değil; bu yüzden
bir `char` değeri her zaman bir karakterdir, ama bir bayt her zaman bir karakter
**değildir**. Dört harfli `"ağaç"` kelimesinin altı bayt tutması, bu ayrımın somut
sonucudur: kelimeyi bayt bayt okumaya çalışan bir kod, ortadaki iki harfi yanlış yerden
bölerdi; `chars()` bu bölünmeyi engelleyip her seferinde tam bir kod noktası veriyor. İki
kelimenin yan yana konması, farkın yalnız Türkçeye özgü harflerde ortaya çıktığını da
gösteriyor — salt ASCII karakterlerden oluşan bir dizgide bayt sayısı ile karakter sayısı
zaten örtüşüyor, çünkü ASCII'nin her karakteri tek bir baytla temsil ediliyor.

Bu ayrımın kaynak üzerindeki karşılığı şu: bir dizginin uzunluğunu okurken hangi sorunun
sorulduğuna dikkat etmek gerekiyor. "Kaç bayt tutuyor" sorusunun yanıtı depolama ve ağ
üzerinden taşıma için önemlidir; "kaç karakter içeriyor" sorusunun yanıtı ise kullanıcıya
gösterilecek uzunluk için önemlidir. İkisi aynı dizgi için farklı sayılar verebildiğinden,
bir kod tabanının hangi soruyu sorduğunu bilmemesi, ölçülemeyen bir hata sınıfına
dönüşebilir.

Bu ders boyunca ölçülen altı tip (beş temel tip ve `()`) hep aynı iki soruyla karşılandı:
bu tipin ürettiği değer kümesi nedir ve bu kümenin sınırı nereden geliyor. Tam sayı ve
karakter için sınır bit genişliğinden geldi; demet için sınır bileşen sayısından; `()` için
sınır tipin tanımından — tek bir değer. Bu sorular önceki iki dersteki sınırlayıcı
ölçümlerle aynı yöntemi izliyor: bir garantinin kapsamını, garantiyi veren yapının kendi
tanımına bakarak çizmek. Sıradaki derste bu altı tip artık hazır malzeme olarak kullanılacak
ve odak, bu malzemelerin bir gövde içinde nasıl bir araya getirilip tek bir dönüş değerine
dönüştüğüne kayacak.

#### Özet

- Beş temel tip (tam sayı, kayan noktalı, mantıksal, karakter, demet) birer ifade olarak
  koşturulduğunda kendi tipinde bir değer üretir; demedin bileşenleri hem indeksle (`.0`)
  hem yapısökümle (`let (a, b) = ...`) okunabilir.
- `()` gerçek bir tiptir ve tek bir değeri vardır; bir deyimin ürettiği şey yokluk değil,
  tam olarak bu tipin o tek değeridir.
- Tam sayı taşması Rust'ta tanımsız değildir; `wrapping_add` gibi yöntemler taşmanın nasıl
  ele alınacağını açıkça belirler ve sonuç her koşumda aynıdır.
- Sabit bit genişlikli tam sayı tipleri (`u8`, `i32` gibi) makineye göre değişmez; bu,
  işaretçi genişliğine bağlı tiplerden ayrı bir sınıftır.
- Bir `char` bir Unicode kod noktasıdır, bir bayt değildir; bir dizginin bayt uzunluğu ile
  karakter sayısı farklı sayılar olabilir.
- Bir demedin tipi bileşenlerin hem tipleriyle hem sayısıyla belirlenir; sayı derleme
  zamanında sabittir ve yapısöküm deseninin sağdaki demetle birebir eşleşmesini zorunlu
  kılar.

#### Sonraki Adım

Değerlerin tipleri artık tanımlı, ama bu değerleri üreten yazımların çoğu şimdiye kadar tek
satırlık ifadelerdi. Sıradaki ders bir gövdenin **tamamının** nasıl bir değer ürettiğini
sorar — bir fonksiyonun son satırının noktalı virgülle bitip bitmemesinin dönüş değerini
nasıl belirlediğini ve bu satırın ne zaman `return` yazmayı gerektirdiğini koşturarak
gösterir. `()` orada da karşımıza çıkacak: gövdesi yalnız bir yan etki üreten bir işlevin
dönüş tipi neden hiç yazılmadan da geçerli olduğu, bu dersin kurduğu tanımın doğrudan bir
sonucu olarak görülecek.

### Fonksiyonlar ve İfade Odaklılık

Source: https://academia.sh/tr/kurslar/rust-temelleri/fonksiyonlar-ve-ifade-odakliligi

Bir fonksiyonun gövdesi bir bloktur ve blok zaten bir ifadedir: son satır noktalı virgülsüzse gövdenin — dolayısıyla fonksiyonun — dönüş değeri odur, noktalı virgül eklenince gövde () döndürür; noktalı virgül değeri atar ama atılan değerin hesaplanması yine de gerçekleşir ve bu, atılan değerin kendi yan etkisiyle gösterilir.

Önceki dört ders sırasıyla üç sınıfı, kaynağın zorunlu iskeletini, bağlamayı ve temel
tipleri kurdu. Bu ders hepsini tek bir noktada birleştiriyor: bir fonksiyonun gövdesi bir
**bloktur** ve blok zaten Rust'ın Tasarım Hedefleri dersinde bir ifade olarak tanımlanmıştı.
Bir fonksiyonun dönüş değeri, dolayısıyla, ayrı bir mekanizma değildir — gövde bloğunun
kendi değeridir. Bu ders kursun eksenini en açık biçimde taşıyor: noktalı virgülün varlığı
ya da yokluğu, bir fonksiyonun ne döndürdüğünü tek başına belirliyor.

Bu, "fonksiyon" kavramının Rust'ta neden ayrı bir dönüş sözdizimine ihtiyaç duymadığını
açıklıyor. Birçok yazımda bir fonksiyonun dönüş değeri, gövdenin geri kalanından ayrı,
kendi başına bir yapı gibi ele alınır. Rust bunun yerine daha önce kurulmuş bir kuralı
yeniden kullanıyor: bir fonksiyon çağrıldığında yapılan şey, gövdesini bir blok olarak
değerlendirmektir ve blok değerlendirmesinin sonucu ne ise fonksiyonun sonucu da odur.
Yeni bir kavram öğrenmek gerekmiyor — önceki derslerde kurulan "blok bir ifadedir" kuralı,
burada bir fonksiyon çağrısının tamamını açıklamaya yetiyor.

#### Gövdenin Son Satırı Dönüş Değeridir

Bir blok, önceki derslerde görüldüğü gibi, son satırı noktalı virgülsüzse o satırın
değerini verir; noktalı virgülle bitiyorsa ya da boşsa `()` verir. Bir fonksiyonun gövdesi
de bir blok olduğu için aynı kural onun için de geçerli: gövdenin son ifadesi noktalı
virgül almazsa, fonksiyonun kendisi o değeri döndürür.

Bu kural gövdenin **her** satırı için değil, yalnız **son** satırı için geçerli. Bir
fonksiyon gövdesindeki ara satırların hepsi normal deyimlerdir ve genellikle noktalı
virgülle biter — `let` bağlamaları, yan etkili çağrılar, döngüler. Yalnız gövdenin en son
satırı özel bir konumdadır: orası **tail konumu**dur ve bloğun kendisinin (dolayısıyla
fonksiyonun) değerini belirleyen tek yer. Aşağıdaki örnek bu tek satırlık kuralın etkisini
iki farklı gövde üzerinden gösteriyor.

```rust
// fonksiyon_govdesi.rs — govdenin son satiri donus degerini belirler
fn hesapla_ve_izle(x: i32) -> i32 {
    println!("hesaplaniyor: {} icin", x);
    x * 2
}

fn ifade_olarak(x: i32) -> i32 {
    hesapla_ve_izle(x)
}

fn deyim_olarak(x: i32) {
    hesapla_ve_izle(x);
}

fn main() {
    let sonuc = ifade_olarak(21);
    println!("ifade_olarak donus degeri: {}", sonuc);

    let deyim_sonucu = deyim_olarak(21);
    println!("deyim_olarak donus degeri: {:?}", deyim_sonucu);
}
```

```
hesaplaniyor: 21 icin
ifade_olarak donus degeri: 42
hesaplaniyor: 21 icin
deyim_olarak donus degeri: ()
```

`ifade_olarak` ile `deyim_olarak` aynı çağrıyı sarıyor — ikisi de `hesapla_ve_izle(x)`i
çağırıyor — ama gövdelerinin son satırı farklı yazıldı. `ifade_olarak`ta çağrı noktalı
virgülsüz, gövdenin tail ifadesi; `deyim_olarak`ta aynı çağrının sonuna bir noktalı virgül
eklendi. Bu tek karakterlik fark, iki fonksiyonun **imzasını** da değiştirmek zorunda
bıraktı: `ifade_olarak`ın dönüş tipi `-> i32` olarak yazılabilirken, `deyim_olarak`ın dönüş
tipi hiç yazılmadı, çünkü varsayılan dönüş tipi `()`tir ve gövde artık `()` üretiyor. Bu iki
imza birbirinin yerine geçemez — `deyim_olarak`a `-> i32` yazılsaydı, gövdesi `()` ürettiği
için derleyici reddederdi.

**RD13.** Bu, önceki dersteki `birim: ()` örneğiyle aynı olguyu, fonksiyon sınırında
gösteriyor. Bir fonksiyonun dönüş tipi, gövdenin ürettiği değerin tipiyle **birebir**
eşleşmek zorunda; gövde `i32` üretiyorsa imza `-> i32` ya da uyumlu bir tip yazmalı, gövde
`()` üretiyorsa imza ya `()` yazmalı ya da hiç yazmamalı. Bu eşleşme derleme zamanında
denetleniyor — gövde ile imza arasında bir uyumsuzluk, çalışma zamanına hiç ulaşmadan
durduruluyor.

Bu denetimin somut bir sonucu var: `deyim_olarak`ın gövdesine dokunmadan yalnız imzasını
`-> i32` olarak değiştirmek yeterli değildir, çünkü gövde hâlâ `()` üretiyor. Aynı şekilde,
`ifade_olarak`ın gövdesindeki tail çağrısına bir noktalı virgül eklemek de imzayı bozar —
gövde artık `()` üretirken imza hâlâ `-> i32` yazıyor olurdu. Bu iki durumun ikisi de
derleyici tarafından reddedilir; kaynak bloğuna konmuyor çünkü ikisi de bir ret örneğidir,
ama sonucu şudur: gövde ile imza arasındaki bu bağ, kaynağın herhangi bir yerinde tek taraflı
değiştirilemez. Noktalı virgülü eklemek ya da çıkarmak, yalnız gövdenin son satırını değil,
fonksiyonun dış dünyaya verdiği sözü de değiştiriyor.

#### Sınırlayıcı Ölçüm: Noktalı Virgül Bir Değeri Sessizce Atar

Çıktının ilk iki satırı da dikkat çekiyor: `hesaplaniyor: 21 icin` mesajı **iki kez**
basıldı — bir kez `ifade_olarak` çağrısında, bir kez `deyim_olarak` çağrısında. İkinci
çağrının sonucu (`42`) hiçbir yerde kullanılmadı, `deyim_sonucu` yalnız `()` tuttu. Ama
`hesapla_ve_izle`nin içindeki yazdırma satırı yine de çalıştı, çünkü fonksiyonun **gövdesi**
her iki çağrıda da tam olarak koşturuldu; değişen yalnız sonucun ne olduğu değil, sonucun
**nereye gittiğiydi**.

Bu, noktalı virgülün ne yaptığını netleştiriyor: noktalı virgül bir hesaplamayı iptal
etmiyor, yalnız o hesaplamanın **sonucunu** atıyor. `hesapla_ve_izle(x);` yazımı, önce
`hesapla_ve_izle(x)`i tıpkı noktalı virgülsüz hâliyle aynı biçimde çalıştırıyor — içindeki
her satır koşuyor, içindeki her yan etki (burada yazdırma) gerçekleşiyor — sonra üretilen
`42` değerini hiçbir adla saklamadan bırakıyor. Bu atma işlemi **sessizdir**: derleyici bir
uyarı basmaz, çalışma zamanı bir iz bırakmaz; atıldığını gösterecek tek şey, değerin
kendisinin bir sonraki satırda hiçbir yerde görünmemesidir. Bu derste bu sessizliği görünür
kılmanın tek yolu, hesaplamanın içine bağımsız bir yan etki (yazdırma) yerleştirmekti —
yan etki olmasaydı, `deyim_olarak`ın içinde gerçekten bir çarpma işleminin çalışıp
çalışmadığını dışarıdan ayırt edemezdik.

Bu bulgunun pratik bir sonucu var: bir fonksiyonun dönüş değerini görmezden gelmek, o
fonksiyonun içindeki işi görmezden gelmek anlamına gelmiyor. `deyim_olarak(21)` çağrısı,
sonucu hiç okunmasa bile, `hesapla_ve_izle`nin bütün gövdesini çalıştırdı. Bir fonksiyonun
yalnızca bir yan etki için mi yoksa yalnızca bir değer için mi çağrıldığı, kaynakta çağrının
sonuna noktalı virgül konup konmamasından anlaşılıyor — ikisi de aynı işi yapıyor, farklı
olan yalnız sonucun okunup okunmadığı.

Bu gözlem, bir yazdırma makrosu çağrısının neden hem bir yan etki hem de bir dönüş değeri
taşıyabildiğini de açıklıyor: çağrı ekrana bir satır basıyor (yan etki) ve aynı zamanda
`()` değerini üretiyor (dönüş değeri). İki tarafın ayrı ayrı var olması, birinin
kullanılmasının öbürünü iptal etmediğini gösteriyor — bir çağrının sonucu okunmasa bile, o
çağrının içindeki her satır çalışır.

Bu ayrım, önceki dersteki `Vec::push` ile `HashSet::insert` karşılaştırmasının tersinden bir
görünümüdür. Orada aynı iş (ekleme) iki ayrı yönteme iki ayrı sınıf veriyordu, çünkü
yöntemlerin imzaları farklıydı. Burada ise **aynı** çağrı (`hesapla_ve_izle(x)`), çağıran
tarafın onu nasıl yazdığına bağlı olarak iki ayrı sınıfa girebiliyor: noktalı virgülsüz
yazılırsa ifade olarak kullanılıyor, noktalı virgüllü yazılırsa deyim olarak kullanılıyor.
Sınıf orada yöntemin kendi imzasından geliyordu; burada çağıranın tercihinden geliyor —
ama her iki durumda da gövdenin içindeki iş, sınıftan bağımsız olarak aynı kalıyor.

#### `return`'ün Gerektiği Yer

Gövdenin son satırı dönüş değerini belirlediğine göre, `return` anahtar sözcüğü ne zaman
gerekiyor? Yanıt: yalnız gövdenin **doğal sonundan önce** çıkmak istendiğinde. Bir
fonksiyon, koşullu bir dalın içinde erken bir sonuca ulaşıp gövdenin geri kalanını hiç
çalıştırmak istemiyorsa, o erken çıkışı `return` ile yazmak zorunda — çünkü o dal gövdenin
**tail konumunda** değil, ortasında.

Bu, `return`ün bir zorunluluk değil bir **seçim** olduğunu gösteriyor. Önceki bölümdeki her
iki fonksiyon da geçerliydi ve ikisi de derlendi; aralarındaki fark, gövdenin dallanmayı
nasıl düzenlediğiydi. Bir gövde, bütün olası sonuçları tek bir büyük ifadenin dalları olarak
düzenleyebiliyorsa, o ifade tail konumuna yerleştirilip hiç `return` yazılmadan aynı sonuca
ulaşılabiliyor. Bir gövde, bazı durumlarda geri kalan mantığı hiç çalıştırmadan erken
çıkmak istiyorsa, o çıkış tail konumunda **olamaz** — çünkü tail konumu tanım gereği
gövdenin en sonudur ve erken çıkış tam olarak "sona kadar gitme" demektir.

```rust
// erken_donus.rs — return yalniz govdenin dogal sonundan once cikmak icin gerekir
fn isaretle_donusle(x: i32) -> i32 {
    if x < 0 {
        return -1;
    }
    if x == 0 {
        return 0;
    }
    1
}

fn isaretle_ifadeyle(x: i32) -> i32 {
    if x < 0 {
        -1
    } else if x == 0 {
        0
    } else {
        1
    }
}

fn main() {
    for deger in [-5, 0, 5] {
        println!("{}: donusle={} ifadeyle={}", deger, isaretle_donusle(deger), isaretle_ifadeyle(deger));
    }
}
```

```
-5: donusle=-1 ifadeyle=-1
0: donusle=0 ifadeyle=0
5: donusle=1 ifadeyle=1
```

İki fonksiyon da aynı üç sonucu üretiyor, ama yalnız `isaretle_donusle` `return` kullanıyor.
`isaretle_donusle`de her `if` bloğu gövdenin ortasında duruyor — gövde onlardan sonra
`1` satırıyla devam ediyor — bu yüzden erken çıkmak isteyen bir dal, kendi değerini
`return` ile açıkça bildirmek zorunda; aksi hâlde o `if` bloğunun kendisi bir ifade olarak
değerlendirilir ama sonucu hiçbir yere bağlanmaz ve gövde kendi doğal sonuna kadar devam
eder. Burada dikkat edilmesi gereken bir nokta var: `if x < 0 { return -1; }` yazımındaki
`if` bloğunun kendisi hâlâ `()` üretiyor, çünkü `return` bloğun **içinden** fonksiyonun
tamamına atlıyor, bloğun kendisine bir değer bırakmıyor. `return`ün etkisi blok sınırını
aşıyor; noktalı virgül ve tail konumu kuralları yalnız o bloğun **kendi** değerini
belirlerken, `return` doğrudan en dıştaki fonksiyon çağrısına dönüyor. `isaretle_ifadeyle`de ise bütün dallanma tek bir `if`/`else if`/`else` zincirine
toplandı ve bu zincirin **kendisi** gövdenin tail ifadesi oldu; hiçbir dal erken çıkmıyor,
üçü de aynı büyük ifadenin bir parçası olarak değerlendiriliyor ve zincirin seçtiği dal
doğrudan fonksiyonun dönüş değeri oluyor.

**RD14.** `return`, bir ifadenin *değerini* değiştirmiyor; bir ifadenin *ne zaman*
değerlendirileceğini, daha doğrusu gövdenin geri kalanının hiç değerlendirilmeyeceğini
belirliyor. `isaretle_donusle`de `x < 0` doğruysa, `return -1;`den sonraki hiçbir satır
çalışmaz — ikinci `if` bloğu bile değerlendirilmez. `isaretle_ifadeyle`de ise üç dal da aynı
zincirin parçası olduğu için, yalnız biri seçiliyor ama "erken çıkma" diye bir kavram yok;
seçilmeyen dallar hiç değerlendirilmiyor olsa da, bu normal dallanma davranışı, erken çıkış
değil.

Çıktı bu farkı doğrudan göstermiyor — üç değer için de iki fonksiyon aynı sonucu veriyor,
çünkü ikisi de aynı mantığı farklı bir düzenlemeyle koduyor. Farkın nerede yattığını görmek
için koşulan satırların sayısına değil, kaynaktaki **kontrol akışının şekline** bakmak
gerekiyor: `isaretle_donusle`de negatif bir girdi için yalnız bir `if` gövdesi çalışıyor ve
fonksiyon oradan hemen çıkıyor; `isaretle_ifadeyle`de aynı girdi için üç dalın hepsi aynı
zincirin parçası olarak değerlendiriliyor, yalnız biri seçiliyor. İki yaklaşım da doğru
sonuca varıyor, ama birinde "erken çıkış" diye adlandırılabilecek bir an var, öbüründe hiç
yok — orada yalnız bir seçim var.

Bu iki yazım arasındaki tercih bir okunabilirlik sorusudur, doğruluk sorusu değil: ikisi de
aynı üç sonucu üretiyor ve ikisi de eşit derecede geçerli. Ama gövde uzadıkça ve erken
çıkılması gereken özel durum sayısı arttıkça, `return` ile yazılan biçim genellikle özel
durumları tail ifadenin dışına, kendi kontrol noktalarına taşıyarak gövdenin geri kalanını
sadeleştiriyor; tek bir dallanmayla ifade edilebilecek kadar basit gövdeler ise `return`
yazmadan, tek bir tail ifadeyle de aynı sonuca ulaşabiliyor.

`isaretle_donusle`nin yapısı bunu somutlaştırıyor: iki özel durum (`x < 0`, `x == 0`) kendi
kontrol satırlarında ele alınıp gövdenin geri kalanından ayrıştırılmış, geriye kalan tek
genel durum (`1`) ise gövdenin doğal sonunda, hiçbir koşula bağlı olmadan duruyor. Okuyan
taraf ilk iki `if`i "özel durum, buradan çık" olarak, son satırı da "artık geriye kalan tek
olasılık bu" olarak okuyabiliyor. `isaretle_ifadeyle`de ise üç durum da eşit ağırlıkta,
tek bir zincirin parçası olarak sunuluyor — hiçbiri diğerinden "daha erken" ya da "daha
istisnai" değil. İki yazım da doğru, ama okuyana verdikleri sinyal farklı: biri "çoğu
durum geride kalan tek satırdır, öncesindekiler sapmadır" diyor, öbürü "üç durum da eşit
önemde" diyor.

`return` yazılan fonksiyonlarda bir düzen daha var: gövdenin doğal sonu, genellikle en
**genel** ya da en **beklenen** durumu taşır, çünkü oraya ulaşmak, önceki bütün özel
kontrolleri geçmiş olmak demektir. Bu, kaynağı yukarıdan aşağı okuyan biri için bir tür
sıralama sağlıyor: en çok karşılaşılan yol en aza indirgenmiş, özel durumlar öne alınıp
elenmiş oluyor. Bu sıralama Rust'ın zorunlu kıldığı bir kural değil, `return`ün doğal
kullanım biçiminden doğan bir alışkanlık.

Bu ders, kursun ilk dersinde kurulan üç sınıfın (ifade, deyim, öğe) neden yalnız tek tek
satırlar için değil, **bütün bir fonksiyon gövdesi** için de geçerli bir çerçeve olduğunu
gösterdi. Bir `fn` bildirimi öğedir ve kendisi değer üretmez; ama o öğenin gövdesi bir
bloktur, blok bir ifadedir ve bir ifadenin ürettiği değer — burada da her zamanki gibi —
son satırın noktalı virgül taşıyıp taşımadığına bağlıdır. Kaynaktaki en küçük birim (tek bir
satır) ile en büyük birimlerden biri (bir fonksiyonun tamamı) aynı kuralla okunabiliyor;
kursun başında kurulan sınıflandırma, ölçeği büyüdükçe yeni bir istisna kazanmıyor.

#### Özet

- Bir fonksiyonun gövdesi bir bloktur; blok zaten bir ifadedir ve son satırı noktalı
  virgülsüzse o satırın değerini, noktalı virgüllüyse `()`i üretir — fonksiyonun dönüş
  değeri bu üretilen değerdir.
- Gövdenin ürettiği değerin tipi, fonksiyonun bildirdiği dönüş tipiyle birebir eşleşmek
  zorundadır; bu eşleşme derleme zamanında denetlenir.
- Noktalı virgül bir hesaplamayı iptal etmez, yalnız sonucunu sessizce atar; atılan
  hesaplamanın içindeki yan etkiler yine de gerçekleşir.
- `return` yalnız gövdenin doğal sonundan önce çıkmak için gerekir; bütün dallanma tek bir
  tail ifadeye toplanabiliyorsa `return` hiç yazılmaz.
- Aynı sonucu üreten iki yazım (erken çıkışlı ve tail-ifadeli) eşit derecede geçerlidir;
  seçim okunabilirlikle ilgilidir, doğrulukla değil.

#### Sonraki Adım

Bu derste `if`/`else if`/`else` zinciri zaten bir ifade olarak kullanıldı, ama denetim
akışının beş biçiminin (`if`, `match`, `loop`, `while`, `for`) hangilerinin değer ürettiği
tek tek ölçülmedi. Sıradaki ders bu beşini yan yana koşturur ve bir `if`in dallarının neden
hep aynı tipte olmak zorunda olduğunu, bir döngünün ne zaman değer üretip ne zaman hiç
üretmediğini gösterir. `isaretle_ifadeyle`nin üç dalının da `i32` döndürmesi bir rastlantı
değildi — dallardan biri farklı bir tip dönseydi bu gövde hiç derlenmezdi; bu kısıtın
kaynağı sıradaki dersin konusu.

### Denetim Akışı

Source: https://academia.sh/tr/kurslar/rust-temelleri/denetim-akisi

if, match, loop, while, for — beş denetim akışı biçiminden yalnız üçü bir değer üretebilir: if ve match birer ifadedir ve bütün dallarının aynı tipi vermesi zorunludur, loop yalnız break ile değer verir, while ve for hiçbir zaman vermez; etiketli bir break, iç içe döngülerden bir değeri doğrudan dışarıya taşıyabilir.

Önceki ders `if`/`else if`/`else` zincirini zaten bir ifade olarak kullandı, ama bu beş
denetim akışı biçiminden (`if`, `match`, `loop`, `while`, `for`) yalnız birinin durumunu
gösterdi. Bu ders beşini birden yan yana koşturuyor ve tek bir soruyu her birine soruyor:
bu biçim, kullanıldığı yerde bir değer üretiyor mu, yoksa yalnız bir iş mi yapıyor?

Bu beş biçim, çoğu dilde tek bir kategori altında toplanır — "denetim akışı yapıları" —
çünkü hepsi programın hangi satırların ne sırayla çalışacağını belirler. Rust'ta bu ortak
işlev korunuyor, ama beşi ayrıca ikiye bölünüyor: kimi biçim akışı yönlendirirken bir değer
de üretiyor, kimi biçim yalnız akışı yönlendiriyor. Bu ayrım rastgele değil — kursun baştan
beri sorduğu soruyla aynı eksende duruyor ve bu derste beş biçim üzerinden tek seferde
yanıtlanıyor.

#### Beş Biçim, Üç Yanıt

```rust
// denetim_akisi.rs — bes bicimden kaci deger uretiyor
fn main() {
    let sayi = 7;

    let if_sonucu = if sayi % 2 == 0 { "cift" } else { "tek" };
    println!("if: {}", if_sonucu);

    let match_sonucu = match sayi {
        0 => "sifir",
        n if n % 2 == 0 => "cift",
        _ => "tek",
    };
    println!("match: {}", match_sonucu);

    let mut sayac = 0;
    let loop_sonucu = loop {
        sayac += 1;
        if sayac == 5 {
            break sayac * 10;
        }
    };
    println!("loop: {}", loop_sonucu);

    let mut toplam = 0;
    let while_sonucu = while toplam < 3 {
        toplam += 1;
    };
    println!("while: {:?}", while_sonucu);

    let mut liste_toplami = 0;
    let for_sonucu = for eleman in [1, 2, 3] {
        liste_toplami += eleman;
    };
    println!("for: {:?}", for_sonucu);
    println!("liste_toplami: {}", liste_toplami);
}
```

```
if: tek
match: tek
loop: 50
while: ()
for: ()
liste_toplami: 6
```

Beş biçim üç ayrı yanıt veriyor. `if` ve `match` birer değer üretiyor — hangi dal seçilirse
o dalın değerini veriyorlar. `loop` da bir değer üretiyor, ama yalnız `break`e bir değer
verildiğinde; burada `sayac` beşe ulaştığında `break sayac * 10` çalışıyor ve `loop`un
kendisi `50` değerine dönüşüyor. `while` ve `for` ise hiçbir zaman bir değer üretmiyor —
ikisi de her koşulda `()` veriyor, döngü gövdesi ne yaparsa yapsın. `for` döngüsünün
içindeki `liste_toplami` değişkeni bunu netleştiriyor: döngünün kendi değeri `()`dir, ama
gövdesinin içindeki bir yan etki (bir dış değişkeni güncellemek) döngünün asıl işini
görüyor.

Bu üç yanıt rastgele dağılmıyor; her birinin kaynağı biçimin kendi kurgusunda. `if` ve
`match` **seçicidir** — birden çok dal sunar, tam olarak birini seçer ve dilin doğal
tercihi seçilen dalın değerini bütün ifadenin değeri saymaktır. `loop` **sınırsızdır** —
kendi başına ne zaman duracağını bilmez, bu yüzden bir değeri ancak açıkça `break`e
verildiğinde üretebilir; `break` hiç çağrılmazsa `loop` da hiç bitmez ve "değeri" sorusu
gündeme bile gelmez. `while` ve `for` ise **koşulludur** — döngünün her turu bir koşula
(`while`da açık bir mantıksal ifade, `for`da bir yineleyicinin tükenip tükenmediği) bağlı
ve döngü bu koşul yanlış olduğunda kendiliğinden duruyor. Bu doğal duruşun hangi turda
gerçekleşeceği kaynaktan görünmüyor, bu yüzden dilin bu iki biçime bir değer vermesi
anlamsız olurdu — hangi durumun "sonuç" sayılacağını kaynak kendisi söylemiyor.

Bu üçlü ayrımın bir sonucu daha var: `loop`, sınırsız olduğu için, aslında `while true { }`
ile aynı akışı kurabilir — ikisi de kendiliğinden durmaz. Ama yalnız `loop` bir değer
üretebiliyor, `while true { }` üretemiyor; çünkü `while`ın kendisi, koşulu ne olursa olsun,
hiçbir zaman `break`e bir değer taşıma imkânı sunmuyor. Aynı sınırsız akış, iki farklı
biçimle yazıldığında iki farklı yeteneğe sahip oluyor.

**RD15.** `if` ve `match`in bir değer üretebilmesinin bir koşulu var: bütün dalları
**aynı tipte** bir değer vermek zorunda. Yukarıdaki `if_sonucu` örneğinde her iki dal da
`&str` veriyor; `match_sonucu`da üç dalın üçü de `&str` veriyor. Bir dal başka bir tip
verseydi (örneğin bir dal `&str`, öbürü `i32` verseydi) derleyici reddederdi — çünkü
`if_sonucu` ya da `match_sonucu`nun **tek bir** tipi olmak zorunda ve o tip hangi dalın
seçildiğine bakılmadan, derleme zamanında bilinmek zorunda.

`match_sonucu`daki ikinci dal (`n if n % 2 == 0 => "cift"`) bir **koruma koşulu (match
guard)** taşıyor: `n` deseni `sayi`nin değerini yakalıyor, `if n % 2 == 0` ise bu dalın
yalnız yakalanan değer çift olduğunda seçilmesini sağlıyor. Bu, desen eşlemenin ileride
ayrıca ele alınacak daha geniş bir örneğidir; burada yalnız bir dalın seçilip
seçilmeyeceğine ek bir koşulun karar verebildiğini görmek yeterli — sonucu, dalın hâlâ tek
bir değer (`"cift"`) üretmesi.

Bu kısıt, `match`in koruma koşulu taşıyan dalında da görülen bir başka özelliği açıklıyor:
`match`in kaç dal taşıdığı ve dalların hangi koşullarla seçildiği çalışma zamanına kadar
belli olmayabilir, ama dalların **tipi** hep derleme zamanında bellidir. Derleyici hangi
dalın koşacağını bilmeden de bütün dalların tipini denetleyebiliyor, çünkü tip denetimi
kaynağın tamamına bakıyor, yalnız çalışma zamanında seçilecek tek bir dala değil. Bu, tip
güvenliğinin **hangi dalın seçildiğinden bağımsız** olarak sağlanmasının nasıl mümkün
olduğunu gösteriyor: her dal ayrı ayrı denetleniyor, sonra hepsinin aynı tipte olduğu
doğrulanıyor — hiçbiri koşmadan önce.

#### Etiketli Döngüden Değer Taşımak

`loop`un `break` ile değer üretmesi, iç içe geçmiş döngülerde bir sorun doğuruyor:
`break` en yakın çevreleyen döngüyü kırıyor, ama bazen bir değeri **daha dıştaki** bir
döngüden çıkarmak gerekiyor. Rust bunu döngü etiketleriyle çözüyor.

```rust
// etiketli_donguler.rs — ic ice donguden bir deger disariya tasinir
fn main() {
    let hedef = 6;
    let mut i = 1;
    let sonuc = 'disarisi: loop {
        let mut j = 1;
        loop {
            if j > 5 {
                break;
            }
            if i * j == hedef {
                break 'disarisi (i, j);
            }
            j += 1;
        }
        i += 1;
        if i > 5 {
            break (0, 0);
        }
    };
    println!("bulunan cift: {:?}", sonuc);
}
```

```
bulunan cift: (2, 3)
```

Burada iki `loop` iç içe. İçteki döngünün etiketi yok ve kendi `break`i yalnız kendisini
kırıyor — `j` beşi aştığında bu iç döngü sona eriyor ve dıştaki döngü `i`yi artırarak devam
ediyor. Dıştaki döngü `'disarisi` etiketini taşıyor; `break 'disarisi (i, j)` satırı, içteki
döngünün **tam ortasından**, doğrudan dıştaki döngüyü kırıyor ve `(i, j)` demedini
`sonuc`a taşıyor. `i=2, j=3` çarpımı hedefi (`6`) verdiğinde bu satır çalışıyor ve döngü
zinciri anında sona eriyor.

Bu kalıp, iki boyutlu bir alanda arama yapan her koda tanıdık gelir: bir tabloda, bir
ızgarada ya da iki değişkenli bir arama uzayında belirli bir koşulu sağlayan ilk çifti
bulmak. Etiketsiz `break` kullanılsaydı, koşul sağlandığında yalnız içteki döngü
kırılabilirdi; dıştaki döngü devam eder, `i`yi artırıp taramayı sürdürürdü — sonucu
saklamak için ayrı bir bayrak değişkeni ve dıştaki döngüde ek bir kontrol gerekirdi.
Etiketli `break`, bu ek denetimi ortadan kaldırıp arama sonucunu doğrudan döngü zincirinin
kendi değeri yapıyor.

**RD16.** Etiketli `break`, yalnız hangi döngünün kırılacağını seçmiyor, aynı zamanda
değerin **hangi döngüye** ait olduğunu da belirliyor. `sonuc`un değeri, en dıştaki
`'disarisi loop`un değeridir — içteki döngünün kendisi hiçbir zaman bir değer üretmedi,
üretemez de, çünkü içteki `break;` hiçbir değer taşımıyor. Bir demet döndürme yeteneği
yalnız etiketlenen döngüye ait; iç döngü yalnız kendi akışını kontrol ediyor, dış döngünün
sonucuna doğrudan karışamıyor — o yalnız etiketli `break` ile mümkün.

Kaynaktaki iki `break` satırı bu yüzden aynı anahtar sözcüğü taşısa da farklı işler
yapıyor. Etiketsiz `break;` en yakın çevreleyen döngüyü kırıyor — burada içteki döngüyü —
ve hiçbir değer taşımıyor, çünkü içteki döngü hiç bir sonuca bağlanmadı. Etiketli
`break 'disarisi (i, j)` ise arada kaç döngü olursa olsun doğrudan adı geçen döngüye
atlıyor ve o döngünün değerini belirliyor. Bu iki kullanım aynı derste, aynı dosyada yan
yana durabiliyor, çünkü etiket yalnız hedefi değiştiriyor; söz dizimi ve anahtar sözcük
aynı kalıyor.

Etiketleme yalnız `break` için değil, `continue` için de geçerlidir — bir sonraki tura
etiketli bir döngüden geçmek de aynı `'ad:` söz dizimini kullanır. Bu ders yalnız değer
taşıyan `break`i ölçtü, çünkü kursun ekseni değer üretimidir; `continue`ün etiketlenmesi de
aynı hedefleme mantığını izliyor, yalnız bir değer taşımıyor.

#### Sınırlayıcı Ölçüm: Elsesiz `if` de Bir İfadedir

Buraya kadar görülen her `if` bir `else` dalı taşıyordu. `else` dalı olmayan bir `if` de bir
ifadedir — yalnız değeri her zaman `()`dir.

```rust
// elsesiz_if.rs — elsesiz bir if de bir ifadedir, degeri ()dir
fn main() {
    let sayi = 4;
    let sonuc = if sayi % 2 == 0 {
        println!("cift bulundu: {}", sayi);
    };
    println!("elsesiz if in degeri: {:?}", sonuc);
}
```

```
cift bulundu: 4
elsesiz if in degeri: ()
```

`sonuc` gerçekten bir bağlamaya bağlandı — bu, `if`in bir ifade olarak değerlendirildiğini
kanıtlıyor, çünkü Rust bir deyimi bir bağlamaya bağlamana izin vermez. Ama `sonuc`un değeri
`()`, çünkü koşul sağlanmadığında ne olacağı hiç yazılmadı ve Rust bu boşluğu `()` ile
dolduruyor — sanki görünmeyen bir `else { }` varmış gibi.

Bu, `if`in dallarının "aynı tipi vermesi" kuralının `else`siz durumdaki karşılığıdır: bir
`else`siz `if`in gövdesi, `sayi` gibi bir `i32` üretmeye kalksaydı (`if sayi % 2 == 0 {
sayi }`, hiç `else` yazmadan), derleyici reddederdi. Çünkü yazılmayan `else` dalı örtük
olarak `()` üretiyor sayılıyor ve gövde `i32` üretirse iki "dal" (yazılan gövde, örtük
`else`) farklı tipte olurdu — tıpkı önceki bölümdeki `if_sonucu` örneğinde iki dalın aynı
tipte olması gerektiği gibi. Bir `else`siz `if`in gövdesi bir değer üretecekse, o değer
`()`ten başka bir şey olamaz; aksi hâlde gövdenin sonuna bir noktalı virgül eklenip
değerin sessizce atılması gerekir.

Bu sınır, kaynak yazarken bir kestirme sağlıyor: bir `if` yalnız bir yan etki için
yazılıyorsa (bir yazdırma, bir güncelleme) ve karşıt durumda yapılacak hiçbir şey yoksa,
`else` dalı yazmaya gerek kalmıyor — derleyici zaten `()` bekliyor ve gövde de `()`
üretiyor. `else` yalnız iki dalın da **farklı bir değer** üretmesi gerektiğinde zorunlu
oluyor.

Bu, önceki dersteki noktalı virgül kuralıyla aynı aileden bir gözlem. Orada bir fonksiyon
gövdesinin son satırına noktalı virgül eklemek, gövdenin ürettiği değeri `()`e çeviriyordu;
burada bir `if`in `else` dalını hiç yazmamak, aynı sonuca farklı bir yoldan ulaşıyor —
yazılmayan dal, örtük olarak `()` üretiyor sayılıyor. İkisi de aynı ilkeyi taşıyor: Rust'ta
bir "eksik" değer, kaynağın hiçbir yerinde tanımsız bırakılmıyor; eksik olan yer hep `()`e
karşılık geliyor.

Beş biçimin üçe ayrılması, kaynağı yazarken de bir seçim sunuyor: bir hesaplamayı belirli
sayıda dal arasından seçen bir yapıya mı ihtiyacın var (`if`, `match`), yoksa durma koşulu
önceden bilinmeyen, açık uçlu bir tekrara mı (`loop`), yoksa sonu koşuldan önceden belli bir
tekrara mı (`while`, `for`)? Bu üç soru birbirinden bağımsızdır ve her birinin yanıtı, o
biçimin değer üretip üretmeyeceğini de beraberinde getiriyor. Bir programcı "bu döngü bana
bir sonuç verecek mi" sorusunu sormadan önce, hangi döngü biçimini seçtiğine bakması
yeterli — yanıt biçimin kendisinde saklı.

Bu ders, altı derslik bu bölümün topladığı bütün parçaları tek bir yerde birleştiriyor.
İlk ders üç sınıfı (ifade, deyim, öğe) tanımladı ve bir ölçüm çekirdeğiyle sayıya döktü;
ikinci ders bu sınıfların proje düzeyinde de geçerli olduğunu gösterdi; üçüncü ders bağlamayı
kurdu; dördüncü ders bağlanan değerlerin tiplerini kurdu; beşinci ders bir fonksiyon
gövdesinin bu üç sınıfı nasıl tek bir dönüş değerinde topladığını gösterdi. Bu ders, son
olarak, denetim akışının kendisinin — programın hangi satırın ne zaman çalışacağını
belirleyen beş biçimin — aynı üç sınıfa nasıl uyduğunu ölçtü. Kaynakta yazılan hiçbir şey bu
sınıflandırmanın dışında kalmadı: en küçük bir işleçten en büyük bir denetim yapısına kadar,
her satır ya bir değer üretiyor ya `()` üretiyor ya da yalnız bir ad bildiriyor. Bu, altı
dersin başında sorulan tek sorunun — kaynakta yazdığın bu şey bir değer mi üretiyor — neden
tek bir dersle sınırlı kalmayıp bir bölümün tamamını taşıyabildiğini de açıklıyor: soru
büyümüyor, yalnız uygulandığı yazım genişliyor.

#### Özet

- Beş denetim akışı biçiminden üçü değer üretebiliyor: `if`, `match` her zaman (bir dal
  seçilerek), `loop` yalnız `break`e bir değer verildiğinde.
- `while` ve `for` hiçbir zaman değer üretmiyor; ikisi de her koşulda `()` veriyor.
- `if` ve `match`in bütün dalları aynı tipte bir değer vermek zorunda; aksi hâlde derleyici
  reddeder.
- Etiketli bir `break`, iç içe döngülerden bir değeri doğrudan en dıştaki etiketli döngüye
  taşıyabiliyor; etiketlenmemiş döngüler yalnız kendi akışlarını kontrol edebiliyor.
- `else`siz bir `if` de bir ifadedir ve değeri her zaman `()`dir; gövdesi başka bir tip
  üretmeye kalkarsa derlenmez.
- Kaynakta yazılan hiçbir şey ifade / deyim / öğe sınıflandırmasının dışında kalmıyor; bu
  ders, denetim akışının en karmaşık biçimlerinin de aynı üç yanıttan birine girdiğini
  gösterdi.

#### Sonraki Adım

Bu altı derste denetim akışının değer üretip üretmediği, tek tek biçimlere bakılarak
ölçüldü. Sıradaki konu aynı soruyu **veriye** taşıyor: bir tip nasıl kuruluyor, kaç durum
taşıyor ve o durumlar nasıl ayrıştırılıyor — yapılar ve numaralandırmalarla başlayan yeni
bir bölüm bu soruları tek tek ele alacak. Şimdiye kadar görülen tipler dilin kendi
sunduğu hazır tiplerdi (tam sayı, kayan noktalı, demet); sıradaki bölümde bu tiplerden
yenilerinin nasıl **tanımlandığı** — alanların bir arada toplanması, durumların bir arada
sayılması — ele alınacak.

## Veri Modelleme

Alanların ve yöntemlerin bir tipte toplanması, veri taşıyan varyantlarla durumların tek tipte sayılması, desen eşlemenin bütünlük istemesi ve yapısöküm, büyüyen dizi ile anahtar-değer yapısının farkı, sıralı ve karma tabanlı yapıların verdiği ayrı güvenceler, modül sınırının görünürlükte karşılığı.

### Yapılar

Source: https://academia.sh/tr/kurslar/rust-temelleri/yapilar

Aynı Nokta değeri üç ayrı yazımla kuruluyor — tam yazım, güncelleme sözdizimi, ilişkili fonksiyon — ve üçü de bir ifade olarak değer üretiyor; struct bildiriminin kendisi hiçbir değer üretmiyor, yalnızca sonraki satırların kullanacağı bir ad tanıtıyor.

Denetim Akışı dersi beş akış biçiminin değer üretip üretmediğini tek tek ölçtü: `if` ve
`match` birer ifadeydi, `loop` yalnızca `break` ile değer taşıdı, `while` ile `for` hiçbir
zaman değer vermedi. Bu ders aynı soruyu farklı bir malzemeye taşıyor. Artık akış biçimleri
değil veri tipleri var ve soru değişmiyor: bir tipten değer kurmak bir ifade mi, yoksa
tipin kendisini kaynağa yazmak mı?

Rust'ta birden çok alanı tek bir tip altında toplamanın yolu yapıdır (struct). Bu ders, bir
yapının **bildirilmesi** ile o yapıdan bir **değer kurulması** arasındaki farkı üç ayrı
yazımla ölçüyor — tam yazım, güncelleme sözdizimi ve ilişkili fonksiyon — ve üçünün de aynı
sınıfa düştüğünü gösteriyor. Bildirimin kendisi hiçbir zaman o sınıfa girmiyor. Dersin
ikinci yarısı ise bildirimin içindekilere, yani alanlara döner: aynı alan kümesi iki farklı
yapı biçiminde — adı olan ve adı olmayan — ne kadar farklı davranıyor, bu da ayrıca
ölçülüyor.

#### Bildirim Bir Öğedir, Değer Kurmak Bir İfadedir

`struct Nokta { x: i32, y: i32 }` satırı çalıştırıldığında hiçbir şey üretmez. Bu satır bir
hesaplama değil, derleyiciye bir ad tanıtan bir bildirimdir: sonraki satırların `Nokta`
adını kullanabilmesinin önkoşuludur, ama kendisi bir değer değildir. Bir önceki dersin
terimiyle bu bir **öğedir** — kaynağın herhangi bir noktasında "çalışmaz", yalnızca orada
durur ve derleyicinin bileceği bir tip ekler.

Buna karşılık `Nokta { x: 3, y: 4 }` yazımı çalıştırıldığında bir değer üretir: iki tam
sayıyı alıp bunları `Nokta` tipinde tek bir değere paketler. Bu bir **ifadedir** — sonucu
bir değişkene bağlanabilir, bir fonksiyona argüman olarak geçirilebilir, bir listeye
eklenebilir. Aradaki fark tam olarak önceki derste kurulan ayrımın kendisidir: biri
değerlendirilmeden orada durur, öbürü değerlendirilip bir değer verir.

**RV1.** — Bir `struct` bildiriminin tek başına hiçbir çıktı üretmediği iddiası burada
ayrı bir koşumla değil, aşağıdaki programın kendisiyle doğrulanıyor: `struct Nokta { ... }`
satırı `main` içinde değil, `main`den önce duruyor ve hiçbir yazdırma çağrısı o satırı
tetiklemiyor. Program çalıştığında görünen tek çıktı, `Nokta` adının **kullanıldığı**
satırlardan geliyor.

Bu ayrımın altında yatan neden, iki satırın derleyici için farklı zamanlarda işlenmesidir.
Bir bildirim derleme zamanında (compile time) okunur: derleyici `Nokta` adını, alanlarını
ve tiplerini tabloya kaydeder, ama bu kayıt işlemi programın çalışma zamanında (runtime)
hiçbir iz bırakmaz. Bir değer kurma yazımı ise çalışma zamanında işler: `Nokta { x: 3, y:
4 }` satırı çalıştığında bellekte gerçekten iki tam sayı bir araya getirilir. `let` ile
kurulan bir bağlamanın (Değişkenler ve Değişmezlik dersinin konusu) çalışma zamanında
gerçekleşmesiyle aynı düzendedir bu — farkı, bağlamanın soluna bir öğe değil bir ifade
gelmek zorunda olmasıdır.

Bu, üç sınıfın en berrak biçimde ayrıştığı yerlerden biridir. Bir **deyim** hâlâ
değerlendirilir — yalnızca sonucu `()`e düşer ya da atılır — ama bir **öğe** hiç
değerlendirilmez; kaynakta durduğu yerde "çalışan" bir şey yoktur. `struct` bildirimi
bu üçüncü kategoriye girer: program çalışırken üzerinden geçilen bir adım değil,
derleyicinin kaynağı okurken bir kez işlediği bir kayıttır.

Aşağıdaki koşum, aynı `Nokta` tipinden değer kurmanın üç ayrı yolunu yan yana koyuyor.

```rust
// yapi_kurma.rs — struct bildirimi bir oge, yapi degeri kurmak bir ifadedir
struct Nokta {
    x: i32,
    y: i32,
}

impl Nokta {
    fn koken() -> Nokta {
        Nokta { x: 0, y: 0 }
    }

    fn boyut(&self) -> i32 {
        self.x.abs() + self.y.abs()
    }
}

fn main() {
    let a = Nokta { x: 3, y: 4 };
    println!("{:<21}: x={} y={}", "tam yazim", a.x, a.y);

    let b = Nokta { y: 9, ..a };
    println!("{:<21}: x={} y={}", "guncelleme sozdizimi", b.x, b.y);

    let c = Nokta::koken();
    println!("{:<21}: x={} y={}", "iliskili fonksiyon", c.x, c.y);

    println!("{:<21}: {}", "yontem sonucu", b.boyut());
}
```

```
tam yazim            : x=3 y=4
guncelleme sozdizimi : x=3 y=9
iliskili fonksiyon   : x=0 y=0
yontem sonucu        : 12
```

**Tam yazım** bütün alanları tek tek verir: `x` ve `y` açıkça yazılır, sonuç `x=3 y=4`
olan bir değerdir. **Güncelleme sözdizimi** (`..a`) bunun bir kısaltmasıdır: yalnızca `y`
alanı yeniden verilir, geri kalan alanlar `a`dan kopyalanır. Sonuç yine tek bir çağrıda
üretilen bir `Nokta` değeridir — sözdizimi farklı, sınıf aynı. **İlişkili fonksiyon**
(`Nokta::koken()`) ise bambaşka bir yoldan aynı sınıfa varır: `x` ve `y` hiç yazılmadan,
işlev çağrısının kendisi bir `Nokta` üretir. Üç yazımın ortak noktası, üçünün de `let` ile
bir ada bağlanabilmesidir — bu, bir ifadenin tanımı gereği zaten mümkündür, bir öğe için ise
anlamsızdır.

#### Yöntem ile İlişkili Fonksiyon: Alıcının Varlığı

`Nokta::koken()` ile `b.boyut()` çağrıları görünüşte benzer: ikisi de `impl Nokta` bloğu
içinde tanımlı, ikisi de bir değer döndürüyor. Aralarındaki fark çağrı sözdiziminde
görünür ve tek bir noktaya iniyor: **alıcının varlığı**.

`koken` fonksiyonunun imzasında `self` yoktur; bu yüzden tip adıyla çağrılır
(`Nokta::koken()`) ve bir örnek gerektirmez. Rust'ın kendi terimiyle bu bir **ilişkili
fonksiyondur** — `Nokta` tipiyle ilişkilidir ama belirli bir `Nokta` değeriyle değil.
`boyut` fonksiyonunun imzasında ise ilk parametre `&self`dir; bu parametre çağrının
hangi değer üzerinde yapıldığını belirtir ve çağrı noktasında görünmez, `b.boyut()`
yazımındaki `b` onun yerini alır. Bu, Rust'ın **yöntem** dediği biçimdir.

Ayrım, işin ne yaptığıyla değil imzanın neyi zorunlu kıldığıyla ölçülür: `self` parametresi
varsa çağrı bir değer üzerinden yapılır (yöntem), yoksa tip adı üzerinden yapılır (ilişkili
fonksiyon). Yukarıdaki koşumda `koken()` hiçbir mevcut `Nokta`ya ihtiyaç duymadan sıfırdan
bir değer üretti; `boyut()` ise yalnızca zaten var olan `b` değeri üzerinden çağrılabildi.
İkisi de birer ifadedir — ikisi de bir değer döndürür — ve bu, ifade/deyim/öğe eksenine
yeni bir dal eklemiyor: Rust'ta `()` dönmeyen her fonksiyon çağrısı zaten bir ifadedir,
yöntem olsun ilişkili fonksiyon olsun. Buradaki ayrım eksenin dışındadır — çağrı
sözdizimine, alıcının olup olmamasına aittir.

`boyut` fonksiyonu, noktanın orijine olan uzaklığını iki mutlak değerin toplamıyla
hesaplıyor: `self.x.abs() + self.y.abs()`. Ölçümde `b`, `x=3 y=9` değerini taşıyordu; bu
yüzden `boyut()` çağrısı `3 + 9 = 12` verdi. `koken` ise adından da anlaşılacağı gibi bir
kurucu görevi görüyor: bir `Nokta` değeri üretmenin yalnızca üç yolundan biri değil, sık
kullanılan bir adlandırma alışkanlığıdır — bir tipin en yaygın başlangıç değerini
`Tip::koken()`, `Tip::bos()` ya da `Tip::varsayilan()` gibi bir ilişkili fonksiyonla
sunmak. Bildirim aşamasında bu fonksiyonların kaç tane olacağına dair bir sınır yoktur;
`impl Nokta` bloğu her ikisini de aynı yerde toplar.

Adlandırılmış yapı sözdizimi yalnızca değer kurarken alan adı ister; yöntem çağrısı
sırasında alan adı hiç görünmez. `b.boyut()` yazımında `b`, çağrının hangi değer üzerinde
yapıldığını belirtir, ama `boyut` fonksiyonunun içinde `self.x` ve `self.y` alanlarına
adıyla erişilir. Alıcı, çağrı sözdiziminde tek bir noktaya (`.`) indirgenmiş görünse de,
fonksiyonun gövdesinde alanlarına adıyla ulaşılan tam bir `Nokta` değeridir.

`self` parametresinin önünde tek bir `&` işareti bulunur. Bu işaretin tam anlamı ve
alıcının değeri neden kopyalamadan kullanabildiği, Sahiplik ve Ödünç Alma dersinin
konusudur; burada ölçülen yalnızca alıcının **varlığının** çağrı sözdizimini nasıl
belirlediğidir, alıcının nasıl aktarıldığı değil.

Bir tipin `impl` bloğunda kaç ilişkili fonksiyon ya da yöntem bulunabileceğine dair bir
üst sınır yoktur. `Nokta` gibi küçük bir tip bile birden çok kurucu ilişkili fonksiyona
sahip olabilir — `koken()` yanında `birim() -> Nokta` ya da `ikisi(x: i32, y: i32) ->
Nokta` gibi başka isimlerle başka varsayılan değerler sunulabilir. Hangi isimlerin
kullanılacağı bir dil kuralı değil, bir adlandırma alışkanlığıdır; derleyici için hepsi
aynı sınıfa, ilişkili fonksiyona, girer.

#### Alan Sırası Adlandırılmış Yapıda Kimlik Taşımaz

Bir yapı değeri kurarken alanların kaynakta yazılma sırası, bildirimdeki sırayla aynı
olmak zorunda değildir. `Nokta { x: 3, y: 4 }` ile `Nokta { y: 4, x: 3 }` aynı değeri
üretir; derleyici her alanı adına göre eşler, konumuna göre değil.

```rust
// alan_sirasi.rs — adlandirilmis yapida alan sirasi kimlik tasimaz
struct Nokta {
    x: i32,
    y: i32,
}

fn main() {
    let d = Nokta { x: 3, y: 4 };
    let e = Nokta { y: 4, x: 3 };
    println!("{:<18}: x={} y={}", "d (x once)", d.x, d.y);
    println!("{:<18}: x={} y={}", "e (y once)", e.x, e.y);
    println!("{:<18}: {}", "d ve e esit mi", d.x == e.x && d.y == e.y);
}
```

```
d (x once)        : x=3 y=4
e (y once)        : x=3 y=4
d ve e esit mi    : true
```

`d` ve `e` kaynakta farklı sırada yazıldı, ama ikisi de aynı `x` ve `y` değerlerine sahip.
Alan adları burada bir konum belirteci değil, bir eşleştirme anahtarıdır: yazım sırası
okurluk tercihidir, anlamı değiştirmez.

Bu, Rust'ın genel çağrı kuralının dışında kalan bir istisnadır. Bir fonksiyon çağrısında
argümanlar konumla eşlenir — `iki_kat(3)` yazımında `3`ün hangi parametreye gideceği,
parametre listesindeki sırasıyla belirlenir, adıyla değil. Yapı kurma sözdizimi bunun tek
istisnasıdır: `{ }` içindeki her `alan: değer` çifti, `struct` bildirimindeki karşılığını
adından bulur. Bu ayrıcalık yalnızca **kurma** sözdizimine aittir; bir yapı değerinin
alanına erişirken (`a.x` gibi) zaten adla erişilir, orada bir "sıra" sorusu hiç
doğmaz.

**RV2.** — "Sıra anlamı değiştirmiyor" iddiası burada ayrı bir alan karşılaştırma yöntemiyle
değil, `d.x == e.x && d.y == e.y` satırının doğrudan alan alan karşılaştırmasıyla
ölçülüyor; bu satır her iki değerin alanlarının tek tek birbirine eşit olduğunu okur, `d`
ile `e`nin kendisini karşılaştırmaz.

#### Demet Yapısında Sıra Tek Kimliktir

Adlandırılmış yapının tam karşıtı demet yapısıdır (tuple struct): alanların adı yoktur,
yalnızca konumu ve tipi vardır. `Renk(u8, u8, u8)` bildirimi üç bayt taşıyan bir tip kurar,
ama bu üç baytın hangisinin "kırmızı" hangisinin "mavi" olduğunu ad değil **konum**
belirler.

```rust
// demet_kimligi.rs — demet yapisinda sira tek kimliktir
struct Renk(u8, u8, u8);

fn main() {
    let kirmizi = Renk(220, 20, 20);
    let Renk(r1, g1, b1) = kirmizi;
    println!("{:<18}: r={} g={} b={}", "Renk(220,20,20)", r1, g1, b1);

    let mavi = Renk(20, 20, 220);
    let Renk(r2, g2, b2) = mavi;
    println!("{:<18}: r={} g={} b={}", "Renk(20,20,220)", r2, g2, b2);
}
```

```
Renk(220,20,20)   : r=220 g=20 b=20
Renk(20,20,220)   : r=20 g=20 b=220
```

Bu **sınırlayıcı ölçümdür**: adlandırılmış yapıda alan sırası serbestken (bir önceki
koşumda `d` ile `e` bunu gösterdi), demet yapısında konum tek kimliktir. `Renk(220, 20,
20)` ile `Renk(20, 20, 220)` aynı üç sayıyı taşımaz — ilkinde ilk konum büyük, ikincisinde
üçüncü konum büyük — ve sonuç iki ayrı renk değeridir. Adlandırılmış yapıda "hangi alan"
sorusunu ad yanıtlar; demet yapısında aynı soruyu yalnızca konum yanıtlar. `Renk(20, 20,
220)` yazımında ilk iki `20`nin hangi alana ait olduğu, o değerin **nerede** durduğuna
bakılarak çözülür.

**RV3.** — Demet yapısında "konum tek kimliktir" iddiası burada aynı üç sayının farklı
konumlara yerleştirilmesiyle, yani `Renk(220, 20, 20)` ile `Renk(20, 20, 220)` çiftinin
üretilmesiyle ölçülüyor: iki çağrı da aynı üç değeri (`20`, `20`, `220`nin bir
permütasyonunu) taşıyor, ama konumları farklı olduğu için sonuçlar da farklı.

Yapısöküm (destructuring) burada da devreye giriyor: `let Renk(r1, g1, b1) = kirmizi;`
satırı, `kirmizi` değerinin üç alanını sırayla `r1`, `g1`, `b1` adlarına bağlıyor. Bu
yazım aslında bir desendir — sağdaki değerin biçimini sol taraftaki adlarla eşler — ve
desenle ayrıştırmanın tam kapsamı sıradaki dersin konusu. Burada yalnızca demet yapısının
alanlarına erişmenin bu yoldan geçtiği görülüyor: adlandırılmış yapıda `a.x` yazılabilirken,
demet yapısında alana adla değil konumla (`renk.0`, `renk.1`, `renk.2`) ya da yapısökümle
erişilir.

Tek alanlı bir demet yapısı, aynı temel tipi taşıyan iki büyüklüğü birbirinden ayırmak
için de kullanılır. `struct Piksel(i32);` ile `struct Milimetre(i32);` ikisi de içeride
bir `i32` taşır, ama derleyici için iki ayrı tiptir; bir `Piksel` değeri, alanı aynı
görünse de, bir `Milimetre` değerinin yerine doğrudan geçmez. Bu, demet yapısının en sık
kullanıldığı biçimdir: mevcut bir tipe yeni bir isim değil, yeni bir **kimlik** kazandırmak.
Adlandırılmış yapıda aynı amaca alan adıyla ulaşılır (`Konum { piksel: i32 }` gibi); demet
yapısı bunu tek bir sarmalayıcı alanla, alan adı hiç yazılmadan yapar.

**RV4.** — Adlandırılmış yapı ile demet yapısı arasındaki karşıtlık, iki ayrı koşumun yan
yana konmasıyla ölçülüyor: `alan_sirasi.rs` sırayı değiştirip sonucun **aynı** kaldığını,
`demet_kimligi.rs` konumu değiştirip sonucun **farklı** olduğunu gösteriyor. İki koşum da
aynı üç girdiyi (üç sayı) kullanıyor; değişen yalnızca tipin adlı mı adsız mı olduğu.

Yapı, Rust'ın veriyi bir arada tutmanın en dolaysız yoludur: sabit sayıda alan, her biri
tek bir tipe bağlı, hepsi aynı anda var. Bu dersin ölçtüğü üç yazım — tam yazım, güncelleme
sözdizimi, ilişkili fonksiyon — hepsi aynı sonuca varır çünkü hepsi aynı sabit alan
kümesini doldurur. Ama her yapı değeri, sabit bir alan kümesine mahkûm değildir; bir
programın modellemesi gereken veri çoğu zaman "ya şu ya bu" biçiminde birden fazla olası
şekle bürünür. Yapı bunu tek başına karşılayamaz — bir `Nokta` her zaman hem `x` hem
`y` taşır, üçüncü bir "hiç taşımıyor" durumu yoktur. Sıradaki ders bu boşluğu dolduran
tipi kuruyor.

#### Özet

- `struct` bildirimi bir öğedir: çalıştırıldığında hiçbir değer üretmez, yalnızca bir ad
  tanıtır.
- Bir yapı değeri kurmanın üç yazımı — tam yazım, güncelleme sözdizimi, ilişkili fonksiyon
  — üçü de birer ifadedir ve bir değer üretir.
- Yöntem ile ilişkili fonksiyon arasındaki fark alıcının (`self`) varlığıdır: yöntem bir
  değer üzerinden, ilişkili fonksiyon tip adı üzerinden çağrılır.
- Adlandırılmış yapıda alan sırası anlam taşımaz; alanlar ada göre eşlenir.
- Demet yapısında (tuple struct) alanların adı yoktur, yalnızca konumu vardır; konum tek
  kimliktir ve değiştirildiğinde sonuç değişir.

#### Sonraki Adım

Bu ders, bir yapının kaç alan taşıdığını ve bu alanların nasıl kurulduğunu ölçtü — ama bir
yapı değeri her zaman aynı alan kümesini taşır. Sıradaki ders aynı soruyu farklı bir
biçime taşıyor: bir tipin, hangi alanları taşıdığı **duruma göre değişen** birden çok
biçimi olabilir mi? Numaralandırmalar (enum), bir değerin aynı tip altında birden fazla
ayrı durumdan birini taşıyabilmesini kurar; bir sonraki soru bu durumların kaynaktan nasıl
okunduğudur.

### Numaralandırmalar

Source: https://academia.sh/tr/kurslar/rust-temelleri/numaralandirmalar

Bir Sekil değeri üç ayrı biçimde kurulabiliyor — hiç veri taşımadan, tek bir sayı taşıyarak, iki sayı taşıyarak — ve üçü de aynı tip altında sayılıyor; varyant kurmak bir ifade, enum bildiriminin kendisi bir öğe. Sınırlayıcı ölçüm varyant sayısının durum sayısıyla karıştırılmaması gerektiğini gösteriyor.

Yapılar dersi, bir `Nokta`nın her zaman hem `x` hem `y` taşıdığını ölçtü: yapı, sabit bir
alan kümesine bağlı, tek bir biçime sahip bir değerdir. Ama bir programın modellemesi
gereken veri çoğu zaman "ya şu ya bu" biçiminde birden fazla olası şekle bürünür — bir
şeklin hiç çizilmemiş olması, bir çember olması ya da bir dikdörtgen olması gibi. Yapı
bunu tek başına karşılayamaz; bu dersin konusu olan numaralandırma (enum), tam bu boşluğu
dolduruyor.

Bir numaralandırma, bir değerin aynı tip altında birden fazla ayrı **varyanttan** birini
taşıyabilmesini kurar. Önceki dersle aynı soru burada da geçerli: bir varyant kurmak
çalıştırıldığında bir değer mi üretiyor, yoksa `enum` bildiriminin kendisi mi bir şey
üretiyor? Yanıt yapılarla aynı düzendedir, ama bu kez alan sayısı değil **varyant sayısı**
ile bir değerin taşıyabileceği durum sayısı arasındaki fark da ölçülüyor.

Bir numaralandırmayı, aynı işlevi görmeyen bir sabitler kümesinden ayıran şey, her
varyantın isteğe bağlı olarak kendi verisini taşıyabilmesidir. Ayrı ayrı tanımlanmış üç
sabit — `BOS`, `CEMBER`, `DIKDORTGEN` gibi — birbirinden bağımsız üç addır; aralarında
"hangisi seçili" sorusuna derleyicinin garanti verdiği bir yanıt yoktur. Bir `enum` ise
tek bir tip kurar ve o tipin her değeri, o an hangi varyantı taşıdığını kendi içinde bilir.
Bu dersin ölçtüğü ilk şey, bu tek tipliğin öğe/ifade ekseninde nasıl göründüğüdür.

#### Bildirim Yine Bir Öğedir, Varyant Kurmak Bir İfadedir

`enum Sekil { Bos, Cember(f64), Dikdortgen(f64, f64) }` satırı, tıpkı bir önceki dersteki
`struct` bildirimi gibi, çalıştırıldığında hiçbir şey üretmez. Bu satır derleyiciye üç ayrı
varyantı olan bir tip tanıtır; kendisi bir öğedir. Buna karşılık `Sekil::Cember(2.0)`
yazımı çalıştırıldığında bir değer üretir — bir tam sayı yerine, `Cember` varyantını taşıyan
ve içinde `2.0`ı barındıran bir `Sekil` değeri. Bu bir ifadedir; sonucu bir değişkene
bağlanabilir, bir listeye eklenebilir, bir fonksiyona geçirilebilir.

**RV5.** — "`enum` bildiriminin tek başına hiçbir şey üretmediği" iddiası, tıpkı bir önceki
dersteki `struct` örneğinde olduğu gibi, ayrı bir koşumla değil aşağıdaki programın
yapısıyla doğrulanıyor: `enum Sekil { ... }` satırı `main`den önce duruyor ve hiçbir
yazdırma çağrısı doğrudan o satırı tetiklemiyor; görünen her çıktı, varyantların
**kurulduğu** ve **kullanıldığı** satırlardan geliyor.

`Bos`, `Cember` ve `Dikdortgen` üç ayrı varyant adıdır ve üçü de tek bir `enum Sekil { }`
bildirimi içinde, virgülle ayrılarak sıralanır. `Cember(f64)` ile `Dikdortgen(f64, f64)`
arasındaki fark parantez içindeki tip sayısıdır: biri tek bir `f64` taşır, öbürü iki
`f64` taşır; `Bos`un parantezi bile yoktur, çünkü hiç veri taşımaz. Bu üç biçim — parantezsiz,
tek alanlı, çok alanlı — bir `enum` bildiriminin izin verdiği bütün varyant türlerini
kapsıyor.

Aşağıdaki koşum, `Sekil` tipinden dört değer kurup her birinin hangi varyanta ait olduğunu
ve alanı ne kadar olduğunu basıyor.

```rust
// sekil_enum.rs — enum bildirimi bir oge, varyant kurmak bir ifadedir
use std::collections::BTreeSet;

enum Sekil {
    Bos,
    Cember(f64),
    Dikdortgen(f64, f64),
}

fn varyant_adi(s: &Sekil) -> &'static str {
    match s {
        Sekil::Bos => "Bos",
        Sekil::Cember(_) => "Cember",
        Sekil::Dikdortgen(_, _) => "Dikdortgen",
    }
}

fn alan(s: &Sekil) -> f64 {
    match s {
        Sekil::Bos => 0.0,
        Sekil::Cember(yaricap) => std::f64::consts::PI * yaricap * yaricap,
        Sekil::Dikdortgen(genislik, yukseklik) => genislik * yukseklik,
    }
}

fn main() {
    let liste = vec![
        Sekil::Bos,
        Sekil::Cember(2.0),
        Sekil::Cember(5.0),
        Sekil::Dikdortgen(3.0, 4.0),
    ];

    println!("{:<20}: {}", "tasinan deger sayisi", liste.len());
    for (i, s) in liste.iter().enumerate() {
        println!(
            "{:<20}: {:<11} alan={:.2}",
            format!("liste[{}] varyanti", i),
            varyant_adi(s),
            alan(s)
        );
    }

    let ayri_varyantlar: BTreeSet<&str> = liste.iter().map(varyant_adi).collect();
    println!("{:<20}: {}", "ayri varyant sayisi", ayri_varyantlar.len());
}
```

```
tasinan deger sayisi: 4
liste[0] varyanti   : Bos         alan=0.00
liste[1] varyanti   : Cember      alan=12.57
liste[2] varyanti   : Cember      alan=78.54
liste[3] varyanti   : Dikdortgen  alan=12.00
ayri varyant sayisi : 3
```

`liste`, dört ayrı çağrıyla kuruldu ve her çağrı bir ifadeydi: `Sekil::Bos`, hiç veri
taşımadan bile bir `Sekil` değeridir; `Sekil::Cember(2.0)` bir ondalık sayı taşıyarak,
`Sekil::Dikdortgen(3.0, 4.0)` iki ondalık sayı taşıyarak aynı sonuca varır. Üçü de
`Vec<Sekil>` içine `push` edilebildi — derleyici için hepsi aynı tip, `Sekil`.

`varyant_adi` ve `alan` fonksiyonları burada bir araç olarak kullanılıyor: her ikisi de
`match` ile bir değerin hangi varyantı taşıdığını okuyor ve varyanta özgü bir sonuç
üretiyor. `match`in kendi kuralları ve dalların bütünlüğü sıradaki dersin konusu; burada
yalnızca veri taşıyan bir varyanttan (`Cember`, `Dikdortgen`) o veriye ulaşmanın bir yol
gerektirdiği görülüyor — veri taşımayan `Bos` varyantından ise okunacak bir alan yok, `alan`
fonksiyonu onun için doğrudan `0.0` veriyor.

`alan` fonksiyonunun verdiği sayılar bunu somutlaştırıyor: `Cember(2.0)`nin alanı
$\pi \times 2^2 \approx 12{,}57$, `Cember(5.0)`in alanı $\pi \times 5^2 \approx 78{,}54$.
İkisi de aynı formülü kullanıyor — yarıçapın karesiyle pi sayısının çarpımı — ama taşınan
sayı farklı olduğu için sonuç da farklı.
`Dikdortgen(3.0, 4.0)`ün alanı ise `12.00`; bu varyant tek bir sayı değil iki sayı taşıyor
ve `alan` fonksiyonu ikisini de okuyup çarpıyor. `Bos` varyantı hiçbir sayı taşımadığından,
onun için hesaplanacak bir alan yok — `alan` bu durumu ayrı bir dalda `0.0` ile karşılıyor.

Varyant adlarını saymak için burada karma küme değil sıralı küme (`BTreeSet`) kullanıldı,
oysa yalnızca `.len()` okunuyor ve bir kümenin eleman sayısı gezinme sırasından
bağımsızdır — bu tek satır için karma küme de aynı sonucu verirdi. Tercih burada bir
zorunluluktan değil, kurs boyunca sürecek bir alışkanlıktan geliyor: çıktısı koşumdan
koşuma değişmeyen bir yapı gerektiğinde sıralı yapı varsayılan seçimdir. Bu seçimin ne
zaman zorunlu, ne zaman yalnızca tutarlılık olduğu Sıralı ve Küme Yapıları dersinin
konusu.

#### Veri Taşıyan ve Taşımayan Varyantlar Aynı Tipte Sayılır

`Sekil` tipinin üç varyantından biri (`Bos`) hiç veri taşımıyor, ikisi (`Cember`,
`Dikdortgen`) taşıyor. Yukarıdaki koşumda `liste.len()` dördü de saydı; `Sekil` tipi
hepsini eşit ağırlıkta tutuyor. Bu, Rust'ın numaralandırmasını bir listeden ("hangi
seçenek?") ayıran temel özelliktir: yalnızca bir ad değil, isteğe bağlı olarak bir de
**yük** taşıyabilir. Veri taşımayan bir varyant, veri taşıyanın yükü sıfır olan özel bir
durumu değildir — ikisi de aynı `enum` bildiriminin eşit değerli birer üyesidir.

Bu eşitlik `Vec<Sekil>` gibi bir koleksiyonun neden mümkün olduğunu da açıklıyor. Bir
koleksiyon tek bir tip taşır; eğer `Bos`, `Cember` ve `Dikdortgen` üç ayrı tip olsaydı,
üçünü aynı listede tutmak mümkün olmazdı. `enum` bunu tek bir tip altında birleştirerek
çözüyor: `Sekil` değişkeninin taşıdığı asıl varyant çalışma zamanında bellekte saklanıyor,
ama derleme zamanında `Sekil` tek bir tip olarak görülüyor.

**RV6.** — "Veri taşıyan ve taşımayan varyantların aynı tipte sayıldığı" iddiası burada
`Vec<Sekil>` içine dördünün birden konabilmesiyle ölçülüyor: eğer varyantlar farklı
tiplerde sayılsaydı, derleyici `liste` içindeki dördüncü öğeyi (`Dikdortgen`) ilkinden
(`Bos`) farklı bir tip olarak reddederdi. Derlemenin sorunsuz geçmesi, `tasinan deger
sayisi: 4` satırının dördünü de saymasıyla birlikte bu eşitliğin doğrudan kanıtıdır.

Varyant adları tek başlarına değil, tip adıyla birlikte yazılır: `Sekil::Cember(2.0)`,
`Cember(2.0)` değil. Bu öneki gerektiren şey, aynı adın birden fazla `enum`da varyant
olarak kullanılabilmesidir — başka bir tipte de `Cember` adında bir varyant tanımlanmış
olsaydı, `Sekil::` öneki olmadan hangi tipin `Cember`inden söz edildiği belirsiz kalırdı.
Bu, bir yapı değerinin kurulmasından (`Nokta { x: 3, y: 4 }`) farklı bir noktadır: yapı
kurma sözdiziminde tip adı zaten baştadır ve tekrar bir öneke gerek kalmaz, ama bir varyant
kurma sözdiziminde tip adı ile varyant adı iki ayrı ad olduğundan aralarına `::` konur.

Bu tek tiplilik, her `Sekil` değerinin hangi varyantı taşıdığını kendi içinde bilmesiyle
mümkün olur: `varyant_adi` fonksiyonu tam olarak bu bilgiyi okuyor; `alan` fonksiyonu ise
hem hangi varyant olduğunu okuyor hem de ona göre farklı alanlara erişiyor. Bir yapıda
böyle bir ayrım yoktur, çünkü bir yapının bütün alanları her zaman aynı andadır — `Nokta`
değeri hiçbir zaman "şu an yalnızca `x`i var" durumuna düşmez. `enum` bunu tersine çevirir:
bir değer, aynı anda yalnızca **bir** varyantın alanlarına sahiptir, diğer varyantların
alanları o değer için hiç yoktur.

Bu, `Sekil::Dikdortgen(3.0, 4.0)` değerinin aynı zamanda bir `yaricap` alanı da taşıdığı
anlamına gelmez — o değer yalnızca `genislik` ve `yukseklik` taşır, `Cember` varyantının
alanı ondan tamamen ayrıdır. `alan` fonksiyonunun `match` ifadesindeki her dal, yalnızca
kendi varyantının alanlarına erişebilir; `Sekil::Cember(yaricap) => ...` dalında `genislik`
adına erişmek mümkün değildir, çünkü o dal yalnızca `Cember` varyantı eşleştiğinde
çalışır ve o anda ortada bir `genislik` yoktur.

Bu, bellekte kaç baytın ayrıldığı sorusuna değinmez — ders böyle bir sayı basmıyor —
yalnızca hangi alanların hangi durumda **erişilebilir** olduğunu ölçüyor. Erişilebilirlik,
`match`in dal yapısıyla dile getirilen bir kaynak-düzeyi kuraldır: bir dalın içine yalnızca
o dalın eşleştiği varyantın alanları girer.

#### Sınırlayıcı Ölçüm: Varyant Sayısı Durum Sayısı Değildir

`Sekil` üç varyant taşıyor: `Bos`, `Cember`, `Dikdortgen`. Ama "üç varyant" ile "üç olası
değer" aynı şey değildir. `Bos`un taşıyabileceği tek bir durum vardır — kendisi. `Cember`
ise bir `f64` taşıyor ve bir `f64`ün alabileceği değer sayısı sayılamayacak kadar
büyüktür. Aynı varyant, farklı yarıçaplarla, sonsuz sayıda farklı **durum** üretebilir.

```rust
// ayni_varyant_farkli_durum.rs — varyant sayisi durum sayisi degildir
enum Sekil {
    Cember(f64),
}

fn main() {
    let kucuk = Sekil::Cember(2.0);
    let buyuk = Sekil::Cember(5.0);

    let Sekil::Cember(r1) = &kucuk;
    let Sekil::Cember(r2) = &buyuk;

    println!("{:<24}: {}", "kucuk cember yaricapi", r1);
    println!("{:<24}: {}", "buyuk cember yaricapi", r2);
    println!("{:<24}: {}", "ayni varyant mi", true);
    println!("{:<24}: {}", "ayni durum mu", r1 == r2);
}
```

```
kucuk cember yaricapi   : 2
buyuk cember yaricapi   : 5
ayni varyant mi         : true
ayni durum mu           : false
```

`kucuk` ile `buyuk`, ikisi de `Cember` varyantını taşıyor — "ayni varyant mi" sorusunun
yanıtı `true`. Ama ikisi aynı durumu taşımıyor: biri `2.0` yarıçaplı, öbürü `5.0` yarıçaplı
— "ayni durum mu" sorusunun yanıtı `false`. Bir önceki koşumda ölçülen "üç ayrı varyant"
sayısı, `Cember` gibi veri taşıyan bir varyantın kaç farklı **durumda** görünebileceğini
söylemiyor.

**RV7.** — Bu sınırlayıcı ölçüm, tek bir kod bloğunda iki ayrı `Sekil::Cember` değeri
kurup ikisinin de aynı varyanttan geldiğini (`true`) ama farklı bir yarıçap taşıdığını
(`r1 == r2` sonucu `false`) yan yana basarak ölçülüyor. "Varyant sayısı" kaynaktan
`enum` bildirimini okuyarak (üç satır, üç varyant) bulunabilirken, "durum sayısı" ancak
programın çalışması sırasında hangi değerlerin üretildiğine bakılarak bulunabilir; ikisi
farklı sorulara yanıt veriyor.

Bu ayrım, veri taşımayan bir varyant için ortadan kalkar. `Bos`un tek bir durumu vardır,
çünkü hiçbir alan taşımaz — varyant sayısı ile durum sayısı orada çakışır. Fark yalnızca
veri taşıyan varyantlarda açılır ve açıldığı andan itibaren durum sayısı taşınan verinin
tipine bağlı hâle gelir: bir `bool` taşıyan bir varyantın iki durumu olur, bir `f64`
taşıyan bir varyantın ise pratikte sınırsız durumu olur.

Bu, tek alanlı bir varyant için bile geçerlidir; alan sayısı arttıkça durum sayısı çarpımsal
büyür. `Dikdortgen(f64, f64)` iki ayrı `f64` taşıyor — genişlik ve yükseklik birbirinden
bağımsız değişebiliyor, bu yüzden bu tek varyantın durum uzayı, bir boyutlu değil iki
boyutlu bir sonsuzluktur. Yukarıdaki koşumda yalnızca `Dikdortgen(3.0, 4.0)` görüldü, ama
kaynakta yazan `Dikdortgen(f64, f64)` bildirimi bundan çok daha fazlasına izin veriyor:
`Dikdortgen(1.0, 1.0)`, `Dikdortgen(0.5, 100.0)` ve sayılamayacak kadar başka çift, hepsi
aynı varyanta ait ama hiçbiri aynı durumu paylaşmıyor.

Bu yüzden "kaç durum" sorusunun yanıtı, `enum` bildirimine bakılarak değil, o bildirimin
alanlarındaki tiplere bakılarak verilir. Veri taşımayan bir varyant durum sayısına tam
olarak `1` katar; sabit sayıda ayrı değer alabilen bir tip taşıyan bir varyant (örneğin
kendisi de sınırlı sayıda varyantı olan başka bir `enum`) o tipin durum sayısı kadar katkı
yapar; `f64` ya da `String` gibi sınırsız bir tip taşıyan bir varyant ise durum sayısını
sınırsız yapar. Kaynaktaki üç satırlık `enum Sekil { ... }` bildirimi bu farkı hiçbir
yerde göstermiyor — üçü de aynı biçimde, birer varyant adı olarak yazılıyor.

Bu ayrımın pratik bir sonucu var: bir `Sekil` değerini ele alan bir kodun doğruluğu,
"üç varyantın hepsi ele alındı mı" sorusuyla ölçülür — "sonsuz durumun hepsi test edildi
mi" sorusuyla değil. `alan` fonksiyonu `Cember(2.0)` için doğru sonucu veriyorsa,
`Cember(5.0)` için de aynı yoldan doğru sonucu verir, çünkü ikisi aynı dalda işleniyor;
tek tek her yarıçapı sınamaya gerek yoktur. Derleyicinin bütünlük denetimi de tam olarak
varyant düzeyinde çalışır, durum düzeyinde değil — bu sınır sıradaki dersin ölçtüğü
"bütünlük" kavramının neye garanti verip neye vermediğini de önceden belirliyor.

Bu ders, bir `Sekil` değerinin kaç ayrı biçim alabileceğini ve bu biçimlerin kaynakta nasıl
kurulduğunu ölçtü. Ama bir değeri kurmak bir yarısı; kurulan değerin hangi varyantı
taşıdığını **okumak** öbür yarısıdır ve bu ders o okumayı yalnızca iki yardımcı
fonksiyonun (`varyant_adi`, `alan`) içinde, arka planda kullandı. `match`in kendisi —
hangi desen biçimlerinin var olduğu, bir dalın ne zaman diğerinden önce geldiği, derleyicinin
neden bütün varyantların ele alınmasını istediği — hiç açılmadı.

#### Özet

- `enum` bildirimi bir öğedir: çalıştırıldığında hiçbir değer üretmez, yalnızca varyantları
  tanımlar.
- Bir varyant kurmak (`Sekil::Cember(2.0)` gibi) bir ifadedir ve bir değer üretir.
- Veri taşıyan ve taşımayan varyantlar aynı `enum` tipi altında eşit ağırlıkta sayılır; bu
  sayede tek bir koleksiyon (`Vec<Sekil>` gibi) hepsini birlikte tutabilir.
- Varyant sayısı, kaynaktaki `enum` bildiriminden okunan sabit bir sayıdır.
- Durum sayısı bundan farklıdır: veri taşıyan bir varyant, taşıdığı verinin tipine bağlı
  olarak bir, birkaç ya da sayılamayacak kadar çok durum üretebilir.

#### Sonraki Adım

Bu ders, bir `Sekil` değerinin kaç ayrı varyant taşıyabileceğini ve varyant kurmanın nasıl
bir ifade olduğunu ölçtü; `varyant_adi` ve `alan` fonksiyonları bu varyantları ayırt etmek
için `match` kullandı ama `match`in kendi kurallarına girmedi. Sıradaki ders tam bu
boşluğu dolduruyor: bir `Sekil` değerinin hangi varyantı taşıdığı kaynakta nasıl okunuyor,
kaç ayrı desen biçimi bunu yapabiliyor ve derleyici bütün varyantların ele alınmasını
neden istiyor?

### Desen Eşleme

Source: https://academia.sh/tr/kurslar/rust-temelleri/desen-esleme

Aynı Cember(5.0) değeri üç ayrı desen biçimiyle ayrıştırılıyor — birebir, bağlayıcı, koşullu — ve match'in kendisi bir ifade olarak bütün dallarda aynı tipi veriyor. Sınırlayıcı ölçüm bir yakalayıcı dalın bütünlüğü sağladığını ama yeni bir varyantı sessizce yutabildiğini gösteriyor.

Numaralandırmalar dersi, bir `Sekil` değerinin kaç ayrı biçim alabileceğini ve bu biçimlerin
kaynakta nasıl kurulduğunu ölçtü — ama kurulan değerin hangi varyantı taşıdığını **okumak**
işini iki yardımcı fonksiyonun içine, arka plana bıraktı. `match`in kendisi hiç açılmadı:
hangi desen biçimleri var, bir dal ne zaman diğerinden önce gelir, derleyici neden bütün
varyantların ele alınmasını ister? Bu ders tam bu üç soruyu açıyor.

`match`, Rust'ta bir değeri desenlerle karşılaştırıp eşleşen ilk dalın gövdesini
çalıştıran yapıdır. Denetim Akışı dersi `match`i zaten bir ifade olarak tanıtmıştı — bir
değer üretir ve bütün dallar aynı tipi vermek zorundadır. Bu ders o tanımı derinleştiriyor:
aynı değer kaç farklı **desen biçimiyle** yakalanabilir ve bu biçimlerin hepsi gerçekten
aynı sınıfa mı düşer?

Desenle ayrıştırmanın kendisi bu kursta yeni bir kavram değildir; bir değerin biçimine
göre dallanma fikri daha önce de kuruldu. Bu derste ölçülen, o fikrin Rust'taki
gerçekleştirimine özgü bir zorunluluktur: eksik bırakılan bir dal, kaynağın derlenmesini
engeller. Bu zorunluluğun kapsamı ve sınırları aşağıda ayrıntılı ölçülüyor.

#### match Bir İfadedir, Bütün Dallar Aynı Tipi Verir

Bir `match` ifadesinin sonucu, hangi dalın eşleştiğine bağlıdır — ama sonucun **tipi**
hangi dalın eşleştiğinden bağımsızdır. Derleyici, `match`in her dalının aynı tipte bir
değer verdiğini derleme zamanında denetler; bir dal `&str`, başka bir dal `i32` verirse
kaynak derlenmez. Bu kural, `match`in bir ifade olmasının doğrudan sonucudur: bir ifadenin
tek bir tipi vardır ve o tip hangi dalın çalıştığına göre değişemez.

Aşağıdaki koşum, tek bir `Sekil::Cember(5.0)` değerini üç ayrı fonksiyonla — üç ayrı desen
biçimiyle — ayrıştırıyor.

```rust
// uc_desen_bicimi.rs — match bir ifadedir, ayni deger uc desen bicimiyle ayristirilir
enum Sekil {
    Bos,
    Cember(f64),
    Dikdortgen(f64, f64),
}

fn siniflandir_birebir(s: &Sekil) -> &'static str {
    match s {
        Sekil::Bos => "bos",
        Sekil::Cember(_) => "cember",
        Sekil::Dikdortgen(_, _) => "dikdortgen",
    }
}

fn siniflandir_baglayici(s: &Sekil) -> String {
    match s {
        Sekil::Bos => "bos".to_string(),
        Sekil::Cember(yaricap) => format!("cember yaricap={}", yaricap),
        Sekil::Dikdortgen(genislik, yukseklik) => format!("dikdortgen {}x{}", genislik, yukseklik),
    }
}

fn siniflandir_kosullu(s: &Sekil) -> &'static str {
    match s {
        Sekil::Cember(yaricap) if *yaricap > 3.0 => "buyuk cember",
        Sekil::Cember(_) => "kucuk cember",
        Sekil::Dikdortgen(genislik, yukseklik) if genislik == yukseklik => "kare",
        Sekil::Dikdortgen(_, _) => "dikdortgen",
        Sekil::Bos => "bos",
    }
}

fn main() {
    let deger = Sekil::Cember(5.0);
    println!("{:<20}: {}", "birebir desen", siniflandir_birebir(&deger));
    println!("{:<20}: {}", "baglayici desen", siniflandir_baglayici(&deger));
    println!("{:<20}: {}", "kosullu desen", siniflandir_kosullu(&deger));

    let kucuk = Sekil::Cember(1.0);
    println!("{:<20}: {}", "kosullu (kucuk)", siniflandir_kosullu(&kucuk));

    let kare = Sekil::Dikdortgen(4.0, 4.0);
    println!("{:<20}: {}", "kosullu (kare)", siniflandir_kosullu(&kare));

    let bos = Sekil::Bos;
    println!("{:<20}: {}", "birebir (bos)", siniflandir_birebir(&bos));
}
```

```
birebir desen       : cember
baglayici desen     : cember yaricap=5
kosullu desen       : buyuk cember
kosullu (kucuk)     : kucuk cember
kosullu (kare)      : kare
birebir (bos)       : bos
```

**RV8.** — "match'in her dalının aynı tipi verdiği" iddiası burada üç ayrı fonksiyonun
kendi dönüş tipi imzasıyla ölçülüyor: `siniflandir_birebir` ve `siniflandir_kosullu`
`&'static str` döndürüyor diye imzalarında yazıyor, `siniflandir_baglayici` `String`
döndürüyor diye yazıyor. Üç fonksiyonun içindeki `match` ifadelerinin her biri, kendi
imzasındaki tek tipe uyuyor; aksi olsaydı kaynak hiç derlenmezdi.

#### Aynı Değer Üç Desen Biçimiyle Ayrıştırılıyor

`siniflandir_birebir`, `siniflandir_baglayici` ve `siniflandir_kosullu` fonksiyonlarının
üçü de aynı `deger` — `Sekil::Cember(5.0)` — üzerinde çalıştı, ama her biri değeri farklı
bir desen biçimiyle yakaladı.

**Birebir desen**, yalnızca hangi varyantın eşleştiğine bakar; taşınan veriye hiç
dokunmaz. `Sekil::Cember(_) => "cember"` dalındaki alt çizgi (`_`), "bu konumda ne olursa
olsun" anlamına gelir — `yaricap`ın değeri `5.0` de olsa `0.3` de olsa fark etmez, dal
yalnızca varyantın `Cember` olup olmadığına bakar. Bu, bir önceki dersteki `varyant_adi`
fonksiyonunun yaptığı işin ta kendisidir; orada da her varyant, taşıdığı veri hiç
okunmadan yalnızca adıyla ayırt ediliyordu.

**Bağlayıcı desen**, varyantı eşleştirmekle kalmaz, taşınan veriyi bir ada da bağlar.
`Sekil::Cember(yaricap) => ...` dalında `yaricap` adı, eşleşen değerin içindeki `5.0`a
bağlanıyor ve dalın gövdesinde bir metin kalıbının içine yerleştirilerek kullanılabiliyor.
Çıktıda görülen `cember yaricap=5` tam olarak bu bağlamanın sonucu.

Bağlayıcı desen ile birebir desen arasındaki fark yalnızca "bir ad yazılıp yazılmadığı"
değildir; bağlanan ad, dalın gövdesinde gerçekten **kullanılabilir** bir değişkendir.
`siniflandir_baglayici` fonksiyonunda `yaricap`, metin kalıbını dolduran bir bağımsız
değişken olarak doğrudan geçiriliyor — tıpkı sıradan bir fonksiyon parametresi gibi
davranıyor. Birebir desendeki alt çizgi
(`_`) ise bir ad değildir, hiçbir yere bağlanmaz; yalnızca "burada bir değer var, ama
onunla ilgilenmiyorum" der.

**Koşullu desen**, bir bağlayıcı desenin üstüne bir de koşul (`if`) ekler; buna Rust'ta
desen koruyucusu denir. `Sekil::Cember(yaricap) if *yaricap > 3.0 => "buyuk cember"`
dalı yalnızca hem varyant `Cember` hem de bağlanan `yaricap` `3.0`tan büyükse eşleşir.
`deger`in yarıçapı `5.0` olduğundan bu koşul sağlanıyor ve sonuç `"buyuk cember"` oluyor;
`kucuk` değeri (`Cember(1.0)`) aynı dala düşmüyor, çünkü koşul sağlanmıyor ve bir alttaki
`Sekil::Cember(_) => "kucuk cember"` dalına düşüyor.

**RV9.** — Üç desen biçiminin de "aynı sınıfta" olduğu iddiası, üçünün de bir `match`
ifadesinin gövdesi olarak bir değer üretmesiyle ölçülüyor: hiçbiri bir yan etki için
yazılmadı, üçü de doğrudan bir fonksiyonun dönüş değeri oldu. Bir desenin birebir mi,
bağlayıcı mı, koşullu mu olduğu, `match`in kendisinin ifade olup olmadığını değiştirmiyor
— üçü de aynı `match ... { desen => değer, ... }` kalıbının birer örneği.

Kare örneği bunu bir adım ileri taşıyor: `Sekil::Dikdortgen(genislik, yukseklik) if
genislik == yukseklik => "kare"` dalı, iki alanı aynı anda bağlayıp ikisini birbiriyle
karşılaştırıyor. `kare` değeri `Dikdortgen(4.0, 4.0)` olduğundan bu koşul da sağlanıyor.
Bir desen koruyucusu, yalnızca bağlanan tek bir adı değil, birden fazla bağlanan adı aynı
anda kullanabilir — bağlamanın kendisi desenin işi, koşulun kendisi ise sıradan bir
mantıksal ifadedir. `genislik == yukseklik` karşılaştırması, `match`e özgü bir yazım
değildir; iki ondalık sayının herhangi bir bağlamda karşılaştırılmasıyla aynı kuralları
izler, yalnızca bu kez desenin bağladığı iki ada uygulanıyor.

`siniflandir_kosullu` fonksiyonundaki dal sırası rastgele değildir. `Sekil::Cember(yaricap)
if *yaricap > 3.0` dalı, koşulsuz `Sekil::Cember(_) => "kucuk cember"` dalından **önce**
yazılıyor; `match` dalları yukarıdan aşağıya sırayla denenir ve ilk eşleşen dal kazanır.
Eğer bu iki dal yer değiştirseydi, `Cember(_)` deseni hiçbir koşul taşımadığından her
`Cember` değerini — büyük olsun küçük olsun — yakalar ve alttaki koşullu dala hiçbir değer
ulaşmazdı. Aynı kural `Dikdortgen` dalları için de geçerli: kare kontrolü, koşulsuz
`Dikdortgen` dalından önce gelmek zorunda, aksi hâlde her dikdörtgen — kare olsun olmasın
— genel dala düşerdi.

Bu sıralama zorunluluğu, `siniflandir_birebir` ve `siniflandir_baglayici`
fonksiyonlarında görülmüyor, çünkü oradaki dalların hiçbiri birbirinin alt kümesi değil:
`Bos`, `Cember(_)` ve `Dikdortgen(_, _)` ayrık varyantlardır, hangi sırada yazılırlarsa
yazılsınlar aynı değeri yakalarlar. Sıralamanın önem kazanması, yalnızca aynı varyantı
hedefleyen birden fazla dal olduğunda — koşullu desenlerde olduğu gibi — ortaya çıkıyor.

#### Bütünlük: Eksik Dal Neden Derlenmiyor

`match`in Rust'a özgü bir kısıtı vardır: bütün dallar, eşleşen değerin **her** olası
varyantını kapsamak zorundadır. Buna bütünlük denir. Yukarıdaki `siniflandir_birebir`
fonksiyonu `Sekil::Bos`, `Sekil::Cember(_)` ve `Sekil::Dikdortgen(_, _)` olmak üzere üç
dal yazdı — `Sekil`in bildirimindeki üç varyantın hepsini. Eğer bu dallardan biri, örneğin
`Sekil::Dikdortgen(_, _) => "dikdortgen"` satırı, kaynaktan çıkarılsaydı, kalan kaynak
derlenmezdi.

Bu ders derlenmeyen bir kaynağı kod bloğuna koymuyor, çünkü derlenmeyen kaynak zaten bloğa
girmiyor — reddedilen bir yazımın çıktısı olmaz, dolayısıyla koşumla doğrulanacak bir
sayı da üretmez; ama reddin nedeni burada tarif edilebilir. Derleyici, `match s { Sekil::Bos =>
..., Sekil::Cember(_) => ... }` gibi eksik bir yazımı gördüğünde, `s`in çalışma zamanında
`Sekil::Dikdortgen` değerini taşıyabileceğini biliyor — çünkü bu, `enum Sekil` bildiriminin
izin verdiği bir varyant. Elindeki dallardan hiçbiri bu olasılığı karşılamadığından,
derleyici hangi kolun çalışacağını söyleyemez ve kaynağı reddeder. Bu ret, çalışma
zamanında "beklenmeyen değer" diye bir hatanın hiç oluşmamasını sağlar: eksik bir dal,
programın çalışmasından önce, derleme sırasında yakalanır.

**RV10.** — Bütünlüğün gerçekten zorunlu olduğu iddiası burada ayrı bir derleyici
çağrısıyla ölçülmüyor — derlenmeyen kaynak kod bloğuna girmediği için — ama dolaylı bir
kanıt var: yukarıdaki üç fonksiyonun her biri, `Sekil`in üç varyantının **tamamını**
kapsıyor. Eğer bütünlük zorunlu olmasaydı, bu üç dalı tam yazmanın bir gerekçesi kalmazdı;
üçü de yalnızca gerekli olduğu için oradadır.

Bütünlük denetimi, kaynaktaki `match`in eşleştiği değerin tipine bakarak çalışır; taşınan
verinin hangi değerleri alabileceğine bakmaz. `Sekil::Cember(f64)` sonsuz sayıda yarıçap
değeri taşıyabilir, ama derleyici bu sonsuzluğu tek tek denetlemez — yalnızca `Cember`
varyantının bir dalda ele alınıp alınmadığını sorar. Numaralandırmalar dersinde ölçülen
"varyant sayısı durum sayısı değildir" ayrımı burada da geçerlidir: bütünlük varyant
düzeyinde bir garantidir, durum düzeyinde değil. Bir dal `Sekil::Cember(yaricap)` yazdığı
sürece, `yaricap`ın hangi değeri taşıdığından bağımsız olarak o varyant kapsanmış sayılır.

#### Sınırlayıcı Ölçüm: Yakalayıcı Dal Bütünlüğü Sağlar Ama Korumaz

Bütünlük kuralını karşılamanın bir kestirme yolu vardır: son dal olarak `_ => ...` yazmak.
Bu dal, kalan bütün varyantları — kaynakta kaçı olursa olsun — tek seferde kapsar ve
derleyiciyi tatmin eder. Ama bu tatmin, dalın gerçekten her varyantı **ayrı ayrı**
düşündüğü anlamına gelmez; yalnızca hiçbirini atlamadığı anlamına gelir.

```rust
// butunluk_yakalayici.rs — yakalayici dal butunluk sagliyor ama korumuyor
enum SekilEski {
    Cember(f64),
    Dikdortgen(f64, f64),
}

enum SekilYeni {
    Cember(f64),
    Dikdortgen(f64, f64),
    #[allow(dead_code)]
    Ucgen(f64, f64, f64),
}

fn etiket_eski(s: &SekilEski) -> String {
    match s {
        SekilEski::Cember(yaricap) => format!("cember r={}", yaricap),
        SekilEski::Dikdortgen(genislik, yukseklik) => format!("dikdortgen {}x{}", genislik, yukseklik),
    }
}

fn etiket_yeni(s: &SekilYeni) -> String {
    match s {
        SekilYeni::Cember(yaricap) => format!("cember r={}", yaricap),
        SekilYeni::Dikdortgen(genislik, yukseklik) => format!("dikdortgen {}x{}", genislik, yukseklik),
        _ => "diger".to_string(),
    }
}

fn main() {
    let eski_cember = SekilEski::Cember(2.0);
    let eski_dikdortgen = SekilEski::Dikdortgen(2.0, 2.0);
    println!("{:<20}: {}", "eski: cember", etiket_eski(&eski_cember));
    println!("{:<20}: {}", "eski: dikdortgen", etiket_eski(&eski_dikdortgen));

    let yeni_cember = SekilYeni::Cember(2.0);
    let yeni_dikdortgen = SekilYeni::Dikdortgen(2.0, 2.0);
    let yeni_ucgen = SekilYeni::Ucgen(3.0, 4.0, 5.0);
    println!("{:<20}: {}", "yeni: cember", etiket_yeni(&yeni_cember));
    println!("{:<20}: {}", "yeni: dikdortgen", etiket_yeni(&yeni_dikdortgen));
    println!("{:<20}: {}", "yeni: ucgen", etiket_yeni(&yeni_ucgen));
}
```

```
eski: cember        : cember r=2
eski: dikdortgen    : dikdortgen 2x2
yeni: cember        : cember r=2
yeni: dikdortgen    : dikdortgen 2x2
yeni: ucgen         : diger
```

`SekilEski` iki varyant taşıyor ve `etiket_eski` ikisini de açıkça, adıyla ele alıyor —
hiçbir yakalayıcı dal yok, çünkü iki dal zaten bütünlüğü sağlıyor. Sonra kaynak
`SekilYeni`ye geçiyor: aynı iki varyant (`Cember`, `Dikdortgen`) korunuyor, ama üçüncü bir
varyant (`Ucgen`) ekleniyor. `etiket_yeni` fonksiyonu, `etiket_eski`yle aynı iki dalı
taşıyor ve üçüncü bir dal yazmak yerine `_ => "diger".to_string()` ekliyor.

Bu kaynak sorunsuz derleniyor — bütünlük sağlanmış durumda, çünkü `_` her varyantı
kapsıyor. Ama `Ucgen(3.0, 4.0, 5.0)` gibi gerçek verisi olan bir değer bu koda girdiğinde,
sonuç yalnızca `"diger"`: üçgenin üç kenar uzunluğu (`3.0`, `4.0`, `5.0`) hiçbir yerde
okunmuyor, hiçbir hesaba katılmıyor. `Ucgen`, `Cember` ve `Dikdortgen`den farklı bir
varyant olduğu hâlde, kod düzeyinde ayrı bir muamele görmüyor.

**RV11.** — "Yakalayıcı dal bütünlüğü sağlar ama korumaz" iddiası burada iki numaralandırma
yan yana koşturularak ölçülüyor: `SekilEski` ile `SekilYeni` aynı iki varyantı (`Cember`,
`Dikdortgen`) taşıyor ve ikisi de aynı iki girdiyle (`2.0` ve `2.0, 2.0`) aynı sonucu
veriyor — `"cember r=2"` ve `"dikdortgen 2x2"`. Fark yalnızca `SekilYeni`nin üçüncü bir
varyant eklemesinde ve `etiket_yeni`nin bu varyantı `_`e bırakmasında. Çıktının son satırı
— `yeni: ucgen : diger` — bu yeni varyantın, kendine özgü bir işlem almadan yakalayıcıya
düştüğünü gösteriyor.

Bu, bütünlüğün ne garanti ettiğini kesin çizgilerle sınırlıyor: derleyici yalnızca "her
varyant için **bir** dal var mı" sorusuna evet diyor; "her varyant kendi mantığıyla ele
alındı mı" sorusuna cevap vermiyor. Bir `enum`a sonradan varyant eklemek, `_` dalı olan bir
`match`i derleme hatası vermeden geçirir — geliştiricinin yeni varyantı fark etmesi için
derleyiciden bir bildirim gelmez, çünkü bütünlük kuralı zaten sağlanmıştır. Yakalayıcısız
bir `match`ta durum farklıdır: yeni varyant eklendiği an, o varyantı kapsamayan her `match`
derlenmeyi durdurur ve geliştiriciyi doğrudan o satıra götürür.

Bu fark, `etiket_eski` ile `etiket_yeni` fonksiyonlarının yazım biçiminde de görünür.
`etiket_eski`, `SekilEski`in iki varyantını da adıyla yazdığı için, `SekilEski`ye üçüncü
bir varyant eklenseydi kaynak derlenmeyi durdururdu — kod, hangi satırın eksik olduğunu
doğrudan gösterirdi. `etiket_yeni` ise `_` dalını taşıdığından, `SekilYeni`ye dördüncü bir
varyant eklense bile derlenmeye devam eder; yeni varyant, önceki üç varyanttan hiçbirine
benzemese de aynı `"diger"` sonucuna düşer. İki fonksiyon da bütünlük kuralını sağlıyor,
ama yalnızca biri, gelecekteki bir değişikliği geliştiricinin gözüne sokuyor.

Bu üç ders — yapılar, numaralandırmalar, desen eşleme — bir veri modelinin üç ayrı sorusuna
yanıt verdi: bir değer hangi alanları taşır, kaç ayrı biçim alabilir ve bu biçimler
kaynaktan nasıl okunur. Şimdiye kadar her ölçüm tek bir değer üzerinden yapıldı — tek bir
`Nokta`, tek bir `Sekil`. Ama gerçek bir programın verisi neredeyse hiçbir zaman tek bir
değerden ibaret değildir; çok sayıda değer bir arada tutulmak zorundadır.

#### Özet

- `match` bir ifadedir; bütün dalları aynı tipte bir değer vermek zorundadır, aksi hâlde
  kaynak derlenmez.
- Aynı değer birebir (yalnızca varyantı denetleyen), bağlayıcı (veriyi bir ada bağlayan) ve
  koşullu (bağlanan veriye bir koşul ekleyen) desenlerle ayrıştırılabilir; üçü de aynı
  `match` yapısının birer örneğidir.
- Bütünlük, bir `match`in eşleşen değerin bütün olası varyantlarını kapsamasını zorunlu
  kılar; eksik bırakılan bir varyant kaynağı derlenmez hâle getirir.
- Bir yakalayıcı dal (`_`) bütünlüğü sağlar ama korumaz: sonradan eklenen bir varyantı
  kendi mantığıyla ele almadan sessizce kapsar.

#### Sonraki Adım

Bu ders, tek bir `Sekil` değerinin nasıl ayrıştırıldığını ölçtü. Ama gerçek programlar
tek bir değeri değil, çok sayıda değeri bir arada tutar — bir listedeki bütün şekiller,
bir sözlükteki bütün adlar. Şimdiye kadar her ders tek bir değişkene bağlanan tek bir
değeri konu etti; sıradaki ders bu sınırı kaldırıyor ve aynı soruyu bir grup değere
taşıyor: çok sayıda değer aynı anda nasıl tutulur ve bu koleksiyonların değiştirici
yöntemleri (ekleme, çıkarma) hangi sınıfa düşer?

### Koleksiyonlar

Source: https://academia.sh/tr/kurslar/rust-temelleri/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?

### Sıralı ve Küme Yapıları

Source: https://academia.sh/tr/kurslar/rust-temelleri/sirali-ve-kume-yapilari

Aynı dört anahtar bir sıralı sözlüğe ve bir karma sözlüğe konuyor: sıralı sözlüğün gezinmesi her koşumda aynı sırayı veriyor, karma sözlüğünki hiç basılmıyor — bu, kursun ortama bağlı veri yasağının en somut örneği. Sınırlayıcı ölçüm sıra güvencesinin bir koşula bağlı olduğunu, Yapılar dersindeki Nokta tipi üzerinden gösteriyor.

Koleksiyonlar dersi karma sözlüğü doğrudan yazdırmadı; anahtarları önce topladı, sıraladı,
ancak öyle bastı. Bu adımın neden gerekli olduğu o derste askıda kaldı. Bu ders — beş veri
modelleme dersinin sonuncusu — tam bu boşluğu dolduruyor: sıralı ve karma yapılar arasındaki
güvence farkı nedir ve bu fark neden kaynakta bir sıralama adımını zorunlu kılıyor?

Şimdiye kadarki dört ders, sırasıyla bir değerin alanlarını, durumlarını, ayrıştırılma
biçimini ve topluca tutulma yollarını ölçtü. Bu ders farklı bir eksende duruyor: iki yapı
arasında bir seçim yapıldığında, bu seçimin **gözlemlenebilir** bir sonucu var mı? Yanıt
evet — ama bu sonuç, iki yapının işlemlerinin çoğunda değil, yalnızca birinde,
gezinmede, ortaya çıkıyor.

Rust'ın standart kitaplığı, hem sözlük hem küme için iki ayrı gerçekleştirim sunar: karma
tabanlı (`HashMap`, `HashSet`) ve sıralı (`BTreeMap`, `BTreeSet`). İkisi de aynı temel
işlemleri — ekleme, sorgulama, silme — destekler ve aynı temel adları taşır: `insert`,
`contains_key` / `contains`, `len`. Bir kaynak, `HashMap` yerine `BTreeMap` yazarak da
çoğu zaman değişmeden çalışmaya devam eder. Aralarındaki fark, işlemlerin sonucunda değil,
yapının **gezinme sırasında** ortaya çıkar — ve bu ders tam olarak bu tek farkı ölçüyor.

#### Küme Eklemek: bool Dönüşü İki Yapıda da Aynıdır

Bir kümeye eleman eklemenin dönüş tipi `bool`dur: eleman gerçekten yeni eklendiyse `true`,
küme zaten o elemanı taşıyorduysa `false`. Bu davranış, sıralı kümede de karma kümede de
aynıdır — sıra güvencesinden bağımsız bir ölçümdür.

```rust
// kume_ekleme_bool.rs — kume eklemek bool doner, sira guvencesinden bagimsiz
use std::collections::{BTreeSet, HashSet};

fn main() {
    let anahtarlar = ["ucgen", "cember", "dikdortgen", "kare"];

    let mut sirali_kume: BTreeSet<&str> = BTreeSet::new();
    for a in anahtarlar {
        let eklendi = sirali_kume.insert(a);
        println!("{:<30}: {}", format!("sirali_kume.insert({})", a), eklendi);
    }
    let tekrar_sirali = sirali_kume.insert("cember");
    println!("{:<30}: {}", "sirali_kume.insert(cember) 2.", tekrar_sirali);

    println!();
    let mut karma_kume: HashSet<&str> = HashSet::new();
    for a in anahtarlar {
        let eklendi = karma_kume.insert(a);
        println!("{:<30}: {}", format!("karma_kume.insert({})", a), eklendi);
    }
    let tekrar_karma = karma_kume.insert("cember");
    println!("{:<30}: {}", "karma_kume.insert(cember) 2.", tekrar_karma);
}
```

```
sirali_kume.insert(ucgen)     : true
sirali_kume.insert(cember)    : true
sirali_kume.insert(dikdortgen): true
sirali_kume.insert(kare)      : true
sirali_kume.insert(cember) 2. : false

karma_kume.insert(ucgen)      : true
karma_kume.insert(cember)     : true
karma_kume.insert(dikdortgen) : true
karma_kume.insert(kare)       : true
karma_kume.insert(cember) 2.  : false
```

Dört farklı anahtar hem sıralı kümeye hem karma kümeye eklendi; her iki yapıda da ilk dört
ekleme `true`, `"cember"`in tekrar eklenmesi `false` verdi. Bu koşum, kümenin **hangi
sırayla** dolaşılacağını hiç sormuyor — yalnızca "bu eleman zaten var mıydı" sorusuna
yanıt arıyor ve bu soru bir kümenin iç sırasından tamamen bağımsız.

Bu, Numaralandırmalar dersinde ölçülen "varyant sayısı durum sayısı değildir" ayrımına
benzer bir düzenektir: `bool` dönüşü, kümenin şu anda kaç eleman taşıdığına ya da onları
nasıl sakladığına bakmadan, tek bir sorunun yanıtını taşıyor. `sirali_kume` ile
`karma_kume` aynı dört anahtarı, aynı sırayla aldı ve ikisi de birbirinden bağımsız
olarak aynı `true, true, true, true, false` dizisini üretti — biri sıralı tutuyor
olmasına, öbürü sıralamıyor olmasına rağmen. Bu, kümeye eklemenin, kümenin gezinme
düzeninden **önce** karar verilen bir soru olduğunu gösteriyor: eleman zaten var mı, yok
mu.

**RV16.** — "Küme eklemenin bool dönüşünün sıra güvencesinden bağımsız olduğu" iddiası,
aynı dört anahtarın hem `BTreeSet`e hem `HashSet`e eklenip ikisinin de birebir aynı
`true`/`false` dizisini vermesiyle ölçülüyor. `sirali_kume` ile `karma_kume`, kaynak
düzeyinde yalnızca tip adlarında farklı — kalan her satır aynı; buna rağmen sonuçlar
satır satır örtüşüyor. Bu örtüşme beş ayrı koşumda da bozulmadı, çünkü `insert`in bool
dönüşü elemanın kümede olup olmadığına bakar, kümenin bellekte nasıl dizildiğine değil.

#### Sıralı Sözlüğün Gezinmesi Her Koşumda Aynıdır

`BTreeMap`, anahtarları her zaman sıralı tutan bir sözlüktür. Bu sıra, ekleme sırasından
değil anahtarların kendi değerlerinden gelir: hangi sırayla eklenirse eklensin, gezinme
her zaman küçükten büyüğe doğru gerçekleşir.

```rust
// sirali_sozluk_gezinme.rs — sirali sozlugun gezinmesi her kosumda ayni
use std::collections::BTreeMap;

fn main() {
    let anahtarlar = ["ucgen", "cember", "dikdortgen", "kare"];
    let mut sirali_sozluk: BTreeMap<&str, i32> = BTreeMap::new();
    for (i, a) in anahtarlar.iter().enumerate() {
        sirali_sozluk.insert(a, i as i32);
    }
    for (anahtar, deger) in &sirali_sozluk {
        println!("{:<27}: {}", format!("sirali_sozluk[{}]", anahtar), deger);
    }
}
```

```
sirali_sozluk[cember]      : 1
sirali_sozluk[dikdortgen]  : 2
sirali_sozluk[kare]        : 3
sirali_sozluk[ucgen]       : 0
```

Anahtarlar kaynakta `"ucgen"`, `"cember"`, `"dikdortgen"`, `"kare"` sırasıyla eklendi —
`ucgen` ilk, `kare` son. Ama çıktıda görünen sıra bambaşka: `cember`, `dikdortgen`, `kare`,
`ucgen` — alfabetik sıra. `BTreeMap` üzerinde dolaşan bir `for` döngüsü, ekleme sırasını
değil, anahtarların **kendi aralarındaki sırasını** izliyor.

Bu, `Vec`in davranışından tamamen farklı bir garantidir. Koleksiyonlar dersinde ölçüldüğü gibi, bir
büyüyen diziyi dolaşmak her zaman ekleme sırasını korur — üçüncü eklenen öğe üçüncü
sırada kalır. `BTreeMap` bu garantiyi vermiyor; anahtarları ekleme sırasından tamamen
koparıp kendi aralarındaki büyüklük ilişkisine göre yeniden diziyor. Bu yeniden dizilme,
tek bir eklemede bile geçerlidir: `sirali_sozluk` içine beşinci bir anahtar, örneğin
`"elips"`, eklenseydi, bu anahtar listenin sonuna değil — alfabetik sıradaki yerine,
`"dikdortgen"` ile `"kare"` arasına — yerleşirdi.

**RV17.** — "Sıralı sözlüğün gezinmesinin her koşumda aynı olduğu" iddiası burada
ölçülmüyor değil, aksine bu dersin kod doğrulaması bu iddianın **ta kendisine** dayanıyor:
yukarıdaki çıktı, bu dersin bir kez koşturulup kaydedilen sabit metniyle karşılaştırılıyor.
Eğer `BTreeMap`in gezinmesi koşumdan koşuma değişseydi, bu karşılaştırma er ya da geç
tutmazdı. Kaydedilen dört satırın sırası — `cember`, `dikdortgen`, `kare`, `ucgen` —
anahtarların alfabetik sırasıyla birebir örtüşüyor; bu, `BTreeMap`in içindeki gerçek
düzenin de bu sırayı izlediğinin dolaylı kanıtı.

Bu belirlenimcilik, kursun bütün derslerinde zaten örtük olarak varsayılan bir kuraldı:
her koşumun, kaynağın bu dosyaya yazıldığı sırada üretilen çıktıyla birebir aynı sonucu
vermesi gerekiyordu. `BTreeMap` bu kuralı kendiliğinden karşılıyor; ekleme sırası ne
olursa olsun, aynı anahtar kümesi her zaman aynı gezinme sırasını üretiyor. Bu, `BTreeMap`i
yalnızca "sıralı" değil, aynı zamanda bu kursun genel gereksinimini karşılayan tek sözlük
gerçekleştirimi yapıyor.

#### Karma Sözlük Doğrudan Gezilmez — Kuralın Kendisi

`HashMap`in gezinme sırası, anahtarların değerinden değil, o çalışma anındaki karma
işlevinin (hash function) başlangıç durumundan gelir; bu durum her program başlangıcında
yeniden ve rastgele belirlenir. Bu rastgelelik bir eksiklik değil, bilinçli bir tasarım
kararıdır: sabit bir karma işlevi kullanan bir sözlük, kötü niyetle seçilmiş girdilerle
kasıtlı olarak yavaşlatılabilir — saldırgan, hangi anahtarların aynı iç kovaya
düşeceğini önceden hesaplayabilir. Karma işlevin başlangıç durumunu her çalıştırmada
yeniden ve rastgele seçmek, bu önceden hesaplamayı imkânsız kılar; bunun bedeli, aynı
programın iki ayrı çalıştırmasının aynı anahtarlar için farklı bir gezinme sırası
üretebilmesidir.

Aynı dört anahtar, aynı sırayla eklense bile, bir koşumda bir sırada, başka bir koşumda
başka bir sırada dolaşılabilir. Kurs boyunca izlenen kural tam burada, kendi gerekçesiyle
birlikte yazılabilir: **bir karma sözlük ya da karma küme, hiçbir derste doğrudan
yazdırılmaz ya da olduğu gibi dolaşılmaz** — çünkü basılan çıktı bu derste doğrulanabilse
bile, bir sonraki koşumda aynı kalacağının hiçbir garantisi yoktur.

Bu kural, karma sözlüğü kullanılamaz yapmıyor; yalnızca **hangi işlemlerin** güvenli
olduğunu sınırlıyor. Belirli bir anahtarla değer okumak, bir anahtarın var olup olmadığını
sormak, toplam eleman sayısını almak — bunların hiçbiri gezinme sırasına bağlı değildir ve
her koşumda aynı sonucu verir. Koleksiyonlar dersinde karşılaşılan `insert`in dönüş
değeri de bu güvenli kümeye girer: bir anahtarın önceki değerini `Some`/`None` olarak
okumak, o anahtarın sözlükte kaçıncı sırada durduğuyla ilgilenmez.

Güvenli olmayan tek işlem, sözlüğün **tamamının** ham sırayla dolaşılıp bu sıranın bir
sonuç olarak kullanılmasıdır — bir `for` döngüsüyle bütün çiftleri gezip bunları oldukları
gibi yazdırmak, ya da ilk ya da son elemanı "gezinme sırasındaki konumuna" göre almak. Bu
derste ve önceki derste her karma yapı, ya tek tek anahtarlarla sorgulandı ya da
dolaşılmadan önce anahtarları ayrıca sıralandı; hiçbir yerde ham gezinme sırası bir sonuç
olarak kullanılmadı.

```rust
// karma_sozluk_tek_anahtar.rs — karma sozluk dogrudan gezilmez, tek anahtar deterministiktir
use std::collections::HashMap;

fn main() {
    let anahtarlar = ["ucgen", "cember", "dikdortgen", "kare"];
    let mut karma_sozluk: HashMap<&str, i32> = HashMap::new();
    for (i, a) in anahtarlar.iter().enumerate() {
        karma_sozluk.insert(a, i as i32);
    }
    println!("{:<28}: {}", "karma_sozluk[cember]", karma_sozluk["cember"]);
    println!("{:<28}: {}", "icerir mi (kare)", karma_sozluk.contains_key("kare"));
    println!("{:<28}: {}", "uzunluk", karma_sozluk.len());
}
```

```
karma_sozluk[cember]        : 1
icerir mi (kare)            : true
uzunluk                     : 4
```

Bu koşumda `karma_sozluk` hiçbir yerde dolaşılmıyor; yalnızca tek bir anahtarla sorgulanıyor
(`karma_sozluk["cember"]`), bir anahtarın varlığı soruluyor (`contains_key`) ve toplam
uzunluk okunuyor (`len()`). Üçü de, sözlüğün içindeki elemanların **hangi sırayla**
dizildiğinden tamamen bağımsız sonuçlar; `"cember"` her zaman `1` değerini taşır, sözlükte
kaçıncı sırada durduğuna bakılmaksızın.

**RV18.** — "Karma sözlüğün tek anahtar sorgusunun deterministik olduğu" iddiası, bu
koşumun beş ayrı çalıştırmada birebir aynı üç satırı vermesiyle ölçülüyor. Bu, `BTreeMap`
örneğindeki gezinme testinden farklı bir ölçüm: orada bütün sözlük dolaşılıp sırası
denetlendi, burada sözlük hiç dolaşılmadan yalnızca noktasal erişimler denetlendi. İki
ölçüm birlikte, "hangi işlemler güvenli, hangileri değil" sınırını tam olarak çiziyor.

Bu sınırın pratik sonucu şudur: bir `HashMap` kullanan bir kaynağın, sözlüğü nasıl
kullandığına bakılmadan "güvensiz" ilan edilmesi doğru olmaz. `karma_sozluk_tek_anahtar.rs`
tam da `HashMap`in en yaygın kullanım biçimini gösteriyor — belirli bir anahtarla değere
ulaşmak, bir anahtarın varlığını sormak — ve bu biçimin hiçbir yerinde gezinme sırasına
ihtiyaç yok. Riskli olan, bir sözlüğün tamamının sırasını **anlamlı** sayan kodun
yazılmasıdır; bu derste yazılan kodun hiçbiri bunu yapmıyor.

#### Sınırlayıcı Ölçüm: Sıra Güvencesi Ücretsiz Değildir

Bir sıralı sözlüğün ya da sıralı kümenin sırayı koruyabilmesi için, anahtar tipinin bir
koşulu karşılaması gerekir: iki anahtar arasında her zaman "hangisi önce gelir" sorusuna
bir yanıt verilebilmelidir. Bu koşula **sıralanabilirlik koşulu** denir ve her tip bunu
karşılamaz.

Yapılar dersinde tanımlanan `Nokta` tipi (`x: i32, y: i32`) bu koşulu karşılamaz. İki
`Nokta` değeri arasında "hangisi önce gelir" sorusunun tek bir yanıtı yoktur — `x`e göre mi
sıralanmalı, `y`ye göre mi, yoksa ikisinin bir bileşimine göre mi? Rust'ın standart
kitaplığı bu kararı `Nokta` için otomatik vermez; `Nokta` değerlerini bir `BTreeSet`e ya da
bir `BTreeMap`in anahtarı olarak koymaya çalışan bir kaynak, sıralanabilirlik koşulu
karşılanmadığı için derlenmez. Bu ders böyle bir kaynağı kod bloğuna koymuyor — derlenmeyen
kaynak bloğa girmiyor — ama ret burada tarif edilebilir: derleyici, `Nokta` için iki
değerin karşılaştırılma yolunu bilmediğini söyler.

**RV19.** — "Sıra güvencesinin ücretsiz olmadığı" iddiası burada olumlu yönden ölçülüyor:
bu derste kullanılan bütün anahtarlar (`&str`) sıralanabilirlik koşulunu zaten karşılıyor
— dizgiler alfabetik olarak karşılaştırılabilir, tam sayılar büyüklüklerine göre
karşılaştırılabilir. `sirali_sozluk_gezinme.rs`in çalışıp beklenen çıktıyı vermesi, bu
koşulun `&str` için sağlandığının dolaylı kanıtı; `Nokta` gibi bu koşulu karşılamayan bir
tipin aynı yapıya girememesi ise koşulun **isteğe bağlı değil zorunlu** olduğunu gösteriyor.

Karma yapılar farklı bir koşul ister: anahtarın karşılaştırılabilir olması değil, bir
karma değere dönüştürülebilir olması gerekir. `Nokta` için bu koşul da otomatik
karşılanmaz. İki koşul birbirinin yerine geçmez — bir tip birini karşılayıp öbürünü
karşılamayabilir — ama ikisinin de ortak noktası, "boş" bir tip üzerinde otomatik
olarak sağlanmamalarıdır; standart kitaplığın kendi tipleri (`i32`, `&str` gibi) bu
koşulları zaten taşır, kullanıcı tanımlı bir tip ise bunu ayrıca kazanmak zorundadır.

Bu, Yapılar dersinde ölçülen bir başka farkı da hatırlatıyor: `Nokta { x: 3, y: 4 }` ile
`Nokta { y: 4, x: 3 }` alan alan eşit olsa da, `Nokta` tipinin kendisi henüz "iki değer
birbirine eşit mi" sorusuna otomatik bir yanıt taşımıyordu — o derste bu karşılaştırma
`d.x == e.x && d.y == e.y` yazılarak elle yapıldı, `d == e` yazılarak değil. Sıralanabilirlik
ve karma alınabilirlik koşullarının ikisi de, önce böyle bir eşitlik koşulunu gerektirir:
iki değerin ne zaman "aynı" sayılacağı bilinmeden, ne sıralama ne de karma değeri
hesaplanabilir. `Nokta` bu eşitlik koşulunu bile henüz otomatik taşımadığından, sıralı ya
da karma bir yapıya doğrudan giremiyor.

Bir tipin bu koşulları nasıl kazandığı — hangi anahtar sözcük ya da bildirim eklenerek —
bu dersin kapsamı dışında kalıyor; burada yalnızca koşulun **var olduğu** ve **her tipte
otomatik sağlanmadığı** ölçülüyor. Standart kitaplığın kendi tipleri bu koşulları
baştan taşıdığı için, bu kursun bütün derslerinde kullanılan anahtarlar — tam sayılar,
dizgiler — hiçbir yerde bu sınırla karşılaşmadı; sınır yalnızca `Nokta` gibi, alanları
programcı tarafından tanımlanmış bir tip söz konusu olduğunda görünür hâle geliyor.

Beş dersin ortak sonucu şudur: Rust'ın veri modelleme araçları — yapı, numaralandırma,
desen eşleme, koleksiyon, sıralı ve karma yapı — hepsi aynı iki soruya farklı açılardan
yanıt verdi. Kaynakta yazılan bir şey bir değer mi üretiyor, yoksa yalnızca bir ad mı
bildiriyor; ve bir işlemin sonucu, o işlemin dönüş tipinden mi okunuyor, yoksa işin
"ne yaptığından" mı tahmin ediliyor. İkinci soru bu son derste özellikle belirginleşti:
`insert`in `bool` dönmesi bir kümenin sıra güvencesiyle hiç ilgilenmiyor; bir sözlüğün
gezinme sırası ise anahtarın kendi tipine bağlı bir koşulun ürünü.

#### Özet

- Küme eklemenin `bool` dönüşü, sıralı ve karma kümede aynı davranır; sıra güvencesinden
  bağımsız bir ölçümdür. Dönüş değeri taşıdığı için ekleme burada bir **ifadedir**.
- Sıralı sözlüğün (`BTreeMap`) gezinmesi anahtarların kendi sırasını izler ve her koşumda
  aynıdır.
- Karma sözlük (`HashMap`) hiçbir derste doğrudan yazdırılmaz ya da dolaşılmaz; yalnızca
  tek anahtar sorgusu, varlık denetimi ve uzunluk gibi sıradan bağımsız işlemler kullanılır.
- Sıra güvencesi bir koşula bağlıdır: anahtar tipinin sıralanabilirlik koşulunu
  karşılaması gerekir; her tip bunu otomatik karşılamaz.

#### Sonraki Adım

Beş veri modelleme dersi burada kapanıyor: yapılar, numaralandırmalar, desen eşleme,
koleksiyonlar, sıralı ve küme yapıları — beş ders boyunca hep aynı soru soruldu, kaynakta
yazılan bir şey bir değer mi üretiyor, yoksa yalnızca bir ad mı bildiriyor. Bu beş dersin
hiçbiri, bu tiplerin ve fonksiyonların kaynağın **neresinde görünebileceğini** sormadı — bir
yapı bildirimi, bir sözlük değişkeni, bir fonksiyon, hangi sınırın içinde tanımlı ve o
sınırın dışından nasıl görülüyor? Kursun kapanış dersi bu soruyu açıyor: modüller ve
kasalar, bütün bunların hangi sınırın içinde göründüğünü belirliyor.

### Modüller ve Kasalar

Source: https://academia.sh/tr/kurslar/rust-temelleri/moduller-ve-kasalar

mod ve use birer öğedir: hiçbiri tek başına bir değer üretmez, biri bir ad sınırı çizer, öbürü var olan bir yolu kısaltır. Aynı ad hem modülün içinden hem dışından çağrılıyor ve pub yazılan/yazılmayan hâller karşılaştırılıyor; iki ayrı kaynak dosyası tek bir rustc çağrısıyla derlenip tek bir kasa oluşturuyor. Sınırlayıcı ölçüm görünürlüğün yolun her halkasında ayrı sağlanması gerektiğini gösteriyor: bir öğe pub olsa bile onu saran modül pub değilse dışarıdan erişilemez.

Beş veri modelleme dersi kapandı ve hep aynı soruyu sordu: kaynakta yazılan bir şey bir değer
mi üretiyor? Bu soru hiçbir yerde, bir tipin ya da bir fonksiyonun kaynağın **neresinde
göründüğüne** değinmedi — bir yapı bildirimi, bir sözlük değişkeni, bir işlev, hangi sınırın
içinde tanımlı ve o sınırın dışından nasıl görülüyor? Kurulum ve Paket Yöneticisi dersi bu
soruyu bir kez ertelemişti: kaynak kökünün gerçek bir projede tek bir dosya olmadığını,
derleyicinin oradan başlayıp başka dosyalara `mod` bildirimleriyle ulaştığını söylemiş, ama
göstermemişti. Bu ders — kursun kapanışı — o ertelenen soruyu açıyor: `mod` ve `use` birer
değer mi üretiyor, yoksa yalnızca bir sınır mı çiziyor; ve bir modülün sınırı ile bir kasanın
sınırı aynı şey mi?

#### `mod` Bir Sınır Çizer, Kendisi Değer Üretmez

Rust'ın Tasarım Hedefleri dersinde `mod olcu { pub fn birim() -> i32 { 3 } }` biçiminde bir
modül zaten görülmüştü ve o dersin ölçüm çekirdeği `mod` bildirimini bir öğe saymıştı — ama
üstünde durmamıştı. Bu ders tam orada duruyor: `mod ad { ... }` satırı çalıştırıldığında
hiçbir şey üretmez. Yapılar dersindeki `struct` bildirimi gibi, derleyiciye bir ad ve bir
sınır tanıtır, kendisi değerlendirilmez. İçindeki her öğe — fonksiyon, sabit, başka bir modül
— ancak **kullanıldığında** bir değer doğurur.

```rust
// mod_ic_dis.rs — mod bir oge, ayni ad hem modul icinden hem disindan cagriliyor
mod olcum {
    pub fn birim() -> i32 {
        3
    }

    fn ozel_carpan() -> i32 {
        10
    }

    pub fn buyutulmus() -> i32 {
        birim() * ozel_carpan()
    }
}

fn main() {
    let disaridan = olcum::birim();
    println!("{:<32}: {}", "olcum::birim() (pub, distan)", disaridan);

    let ictekinden = olcum::buyutulmus();
    println!("{:<32}: {}", "olcum::buyutulmus() (pub, distan)", ictekinden);
}
```

```
olcum::birim() (pub, distan)    : 3
olcum::buyutulmus() (pub, distan): 30
```

**RV20.** `olcum` modülünün bildirimi hiçbir satırda çalışmadı; görülen iki çıktı da
`birim` ve `buyutulmus`ün **çağrıldığı** satırlardan geldi. `birim` adı burada iki ayrı
konumdan çağrılıyor: `main` içinden `olcum::birim()` olarak — modülün dışından, tam yolla —
ve `buyutulmus`ün gövdesinden `birim()` olarak — modülün içinden, hiçbir önek gerekmeden.
Aynı ad, aynı öğe, iki farklı konumdan aynı değeri (`3`) üretiyor; değişen yalnızca çağıranın
modül sınırının hangi tarafında durduğu.

`ozel_carpan` fonksiyonu `pub` taşımadan bildirildi ve yalnızca `buyutulmus`ün gövdesinden,
yani `olcum` modülünün kendi içinden çağrılabildi. Bu, Rust'ta görünürlüğün **varsayılan
olarak kapalı** olduğunu gösteriyor: bir öğe, tanımlandığı modülün dışından, tek bir anahtar
sözcük — `pub` — eklenmeden görünmez. `birim` ile `buyutulmus` bu anahtar sözcüğü taşıdığı
için `main`den erişilebildi; `ozel_carpan` taşımadığı için erişilemedi. Eğer `main` içine
`olcum::ozel_carpan()` yazılsaydı, bu satır derlenmezdi. Bu ret burada kod bloğuna
konmuyor — Desen Eşleme dersinde kurulan kuralla aynı gerekçeyle, derlenmeyen kaynak bloğa
girmiyor — ama nedeni tarif edilebilir: derleyici, çağrının `pub` taşımayan bir öğe üzerinden
modül sınırını geçmeye çalıştığını görür ve kaynağı reddeder.

#### Dosya Sınırı Modül Sınırına Dönüşür — Kasa Tek Derleme Birimidir

Kurulum ve Paket Yöneticisi dersi, kaynak kökünün bu kursta hep tek bir dosya olduğunu, ama
gerçek bir projede derleyicinin oradan başlayıp başka dosyalara `mod` bildirimleriyle
ulaştığını söylemişti. Burada gösteriliyor: `mod ad;` yazımı — gövdesiz, yalnızca noktalı
virgülle biten hâli — derleyiciye aynı dizindeki `ad.rs` dosyasını okumasını ve o dosyanın
**tamamını** `ad` adlı modülün gövdesi saymasını söylüyor.

```rust
// yardimci.rs — mod adi ile cekilen dosyanin tamami modulun govdesidir (KAYNAK)
pub fn disaridan_gorunur() -> i32 {
    ozel_sabit() + 5
}

fn ozel_sabit() -> i32 {
    100
}
```

```rust
// mod_dosya_siniri.rs — mod yardimci; bir dosya sinirini modul sinirina cevirir
mod yardimci;

fn main() {
    let deger = yardimci::disaridan_gorunur();
    println!("{:<34}: {}", "yardimci::disaridan_gorunur()", deger);
}
```

```
yardimci::disaridan_gorunur()     : 105
```

**RV21.** Bu ölçümde iki ayrı kaynak dosyası var — `mod_dosya_siniri.rs` ve `yardimci.rs` —
ama derleme komutu bir kez çalıştı ve tek bir ikili üretti: iki dosya, bir kasa. Bu tek
derleme biriminin adı **kasadır (crate)**: `rustc`e verilen tek bir kaynak kökünden başlayıp
`mod` ile ulaşılan bütün dosyaların bir araya gelmesiyle oluşan, tek bir derleme adımından
geçen bütün. `yardimci.rs` içindeki `ozel_sabit` fonksiyonu `pub` taşımıyor; önceki bölümdeki
kuralın aynısı burada da geçerli — `ozel_sabit`, yalnızca `yardimci` modülünün kendi içinden,
yani `disaridan_gorunur`ün gövdesinden çağrılabiliyor.

Modül ile kasa burada birbirine karışabilir, çünkü ikisi de bir sınır çiziyor, ama çizdikleri
sınırlar farklı düzlemde. Modül bir isim ve görünürlük sınırıdır; kaynağın tek bir dosyada mı
yoksa on dosyada mı durduğuyla ilgilenmez — önceki bölümdeki `olcum` bunu tek dosyanın içinde
gösterdi. Kasa ise bir derleme ve bağlama sınırıdır: kaç dosyadan, kaç modülden oluşursa
oluşsun, tek bir `rustc` çağrısından geçen her şey aynı kasanın parçasıdır. Bir kasa birden
çok modül taşıyabilir — `mod_dosya_siniri.rs` kaynak kökü ile `yardimci` modülü burada aynı
kasanın iki parçasıydı — ama bir modül asla birden çok kasaya bölünmez.

#### `use` Bir Öğedir: Kısayolun Kendisi Değer Üretmez

`mod`un çizdiği sınır bir kez kurulduktan sonra, o sınırın içindeki bir adı her seferinde tam
yoluyla (`olcum::birim()`) yazmak zorunlu değildir. `use` bildirimi bir yolu kısaltan bir
addır ve tıpkı `mod` gibi bir öğedir: satırın kendisi hiçbir değer üretmez, yalnızca sonraki
satırların kullanabileceği kısa bir ad tanıtır.

```rust
// use_oge.rs — use bir oge, deger ancak kisayoldan gelen ad kullaninca dogar
mod olcum {
    pub fn birim() -> i32 {
        3
    }
}

use olcum::birim;

fn main() {
    let kisayoldan = birim();
    let tam_yoldan = olcum::birim();
    println!("{:<30}: {}", "birim() (use sonrasi kisayol)", kisayoldan);
    println!("{:<30}: {}", "olcum::birim() (tam yol)", tam_yoldan);
    println!("{:<30}: {}", "esit mi", kisayoldan == tam_yoldan);
}
```

```
birim() (use sonrasi kisayol) : 3
olcum::birim() (tam yol)      : 3
esit mi                       : true
```

**RV22.** `use olcum::birim;` satırı `main`den önce duruyor ve hiçbir çıktı doğrudan ona
bağlı değil — tıpkı bir önceki bölümdeki `mod yardimci;` gibi, kendisi çalıştırılmıyor.
İki çağrı da — kısayoldan `birim()` ve tam yoldan `olcum::birim()` — aynı değeri (`3`)
üretiyor; `esit mi` satırı bunu doğrudan doğruluyor. `use` bir kısayol tanıtıyor, yeni bir
hesaplama ya da yeni bir davranış değil: kısayoldan gelen değer ile tam yoldan gelen değer
arasında hiçbir fark yok, çünkü ikisi de aynı öğeye, `olcum::birim`e, işaret ediyor. Bu, bir
önceki bölümdeki bulguyla aynı ailededir — bir bildirim kaynağa yeni bir hesaplama eklemez,
yalnızca sonraki satırların okuyabileceği bir ad ekler; `mod` bunu bir sınır için yapar,
`use` aynısını var olan bir sınırın içindeki bir yol için yapar.

#### Sınırlayıcı Ölçüm: Görünürlük Yolun Her Halkasında Ayrı Sağlanır

Buraya kadarki iki ölçüm görünürlüğü tek bir düzeyde gösterdi: bir öğe ya modülün dışına
`pub` taşıyordu ya taşımıyordu. Gerçek sınır bundan biraz daha ince: bir öğe `pub` olsa bile,
onu saran modül `pub` değilse, dışarıdan o öğeye ulaşılamaz.

```rust
// gorunurluk_zinciri.rs — gorunurluk yolun her halkasinda ayri ayri saglanmali
mod dis {
    pub mod ic {
        pub fn deger() -> i32 {
            gizli() + 1
        }

        fn gizli() -> i32 {
            6
        }
    }
}

fn main() {
    let sonuc = dis::ic::deger();
    println!("{:<30}: {}", "dis::ic::deger() (iki pub halka)", sonuc);
}
```

```
dis::ic::deger() (iki pub halka): 7
```

**RV23.** `dis::ic::deger()` çağrısı derlendi ve `7` verdi, çünkü yoldaki iki halka da —
`ic` modülü ve `deger` fonksiyonu — `pub` taşıyor; `dis`in kendisi `pub` taşımıyor ama zaten
kaynak kökünün kendi düzeyinde tanımlı olduğu için dışarıdan (bu dosyanın kendisinden)
görünür durumda. Eğer `ic` modülü `pub` olmadan yalnızca `mod ic { ... }` yazılsaydı, `deger`
fonksiyonunun kendisi hâlâ `pub` kalsa bile `dis::ic::deger()` çağrısı derlenmezdi — çünkü
yol, `pub` taşımayan bir modül sınırından geçmek zorunda kalırdı. Bu kaynak da kod bloğuna
konmuyor, aynı derlenmeyen-kaynak kuralıyla; ama sonucu tarif edilebilir: derleyici için tek
bir öğenin görünürlüğü yetmiyor, yoldaki her adımın görünürlüğü ayrı ayrı sağlanmalı.

Bu, kursun kendi kapanışının sınırıdır da. Buradaki üç ölçüm — tek düzeyli `pub`/`private`
karşıtlığı, dosya sınırının modül sınırına dönüşmesi, çok halkalı görünürlük zinciri —
görünürlüğü ikili (açık ya da kapalı) bir anahtar gibi ele aldı. Rust'ın sunduğu ara
dereceler — yalnızca kasaya açık, yalnızca üst modüle açık gibi — bu derste hiç ölçülmedi,
çünkü ölçü ekseni hâlâ aynı soruydu: kaynakta yazılan bu şey bir değer mi üretiyor. Kaynakta
yazılan `pub` ile `pub` olmayan arasındaki fark tek bir ikili yanıt üretti; bu ikili yanıtın
kendi içindeki ince dereceler, bu eksenin dışında kalan ayrı bir konu.

#### Özet

- `mod` bildirimi bir öğedir: kendisi değer üretmez, yalnızca bir ad ve bir sınır tanıtır;
  aynı ad modülün içinden öneksiz, dışından tam yolla çağrılabilir.
- Görünürlük varsayılan olarak kapalıdır; tek bir `pub` anahtar sözcüğü bir öğeyi modülün
  dışına açar.
- `mod ad;` yazımı bir dosya sınırını modül sınırına çevirir; birden çok kaynak dosyası tek
  bir `rustc` çağrısında derlenip tek bir kasa oluşturabilir.
- `use` bir öğedir: bir yolu kısaltan bir ad tanıtır, kendisi hiçbir değer üretmez; kısayoldan
  ve tam yoldan çağrılan aynı öğe aynı değeri verir.
- Görünürlük yolun her halkasında ayrı sağlanmalıdır: bir öğe `pub` olsa bile onu saran bir
  modül `pub` değilse dışarıdan erişilemez.

#### Kurs Kapanışı

Bu kurs, on iki ders boyunca tek bir soruyu sürdürdü: kaynakta yazılan bir şey bir değer mi
üretiyor, yoksa yalnızca bir ad mı bildiriyor? İlk altı ders bu soruyu dilin en küçük
birimlerine — ifadelere, bağlamalara, temel tiplere, denetim akışına — sordu; sonraki beş
ders aynı soruyu veri modelleme araçlarına — yapılara, numaralandırmalara, desen eşlemeye,
koleksiyonlara, sıralı ve karma yapılara — taşıdı. Bu son ders, sorunun kendisini
değiştirmeden, kaynağın **neresinde** göründüğü sorusunu ekledi: bir öğe hangi sınırın
içinde tanımlı ve o sınırın dışından nasıl görülüyor?

On iki dersin her biri kendi kesitini ölçtü ve kendi sınırlayıcı ölçümünü yazdı; aşağıdaki
tablo bu on iki ölçümü tek bir yerde topluyor.

| Ders | Ölçülen yazım | Sınıfı (ifade · deyim · öğe) | Sınırlayıcı ölçüm |
|---|---|---|---|
| Rust'ın Tasarım Hedefleri | `if`/`match` bir dal seçip değer verir | ifade | Sınıf işin doğasından değil, yöntemin imzasından okunur (`insert` ifade, `push` deyim) |
| Kurulum ve Paket Yöneticisi | giriş noktası, kaynak kökü, bildirim dosyası | öğe | Bildirim dosyası kaynağın içinde değil; kaynak değişmeden yalnız o dosya değişince çıktının adı değişir |
| Değişkenler ve Değişmezlik | `let` bağlaması | deyim | Değişmezlik bağlamanın kendi sınırıdır; verinin başka yoldan paylaşılması ayrı bir soru (K02) |
| Temel Tipler | beş temel tipten değer kurmak | ifade | `()` değersiz değil, tek değerli bir tiptir |
| Fonksiyonlar ve İfade Odaklılığı | gövdenin son satırı (tail konumu) | ifade | Noktalı virgül değeri sessizce atar; hesaplama yine de gerçekleşir |
| Denetim Akışı | `else`siz `if` | ifade | Değeri her zaman `()`dir; gövdesi başka bir tip üretmeye kalkarsa derlenmez |
| Yapılar | `struct` bildirimi | öğe | Demet yapısında sıra tek kimliktir; adlandırılmış yapıda alan sırası serbesttir |
| Numaralandırmalar | `enum` bildirimi | öğe | Varyant sayısı durum sayısı değildir; veri taşıyan bir varyant sayılamayacak kadar durum taşır |
| Desen Eşleme | `match` ifadesi | ifade | Bir yakalayıcı dal bütünlüğü sağlar ama korumaz: sonradan eklenen bir varyantı kendi mantığıyla ele almadan sessizce kapsar |
| Koleksiyonlar | `push` / `insert` | deyim · ifade | `insert`in dönüş değeri bir değişkene bağlanmazsa, üzerine yazılan eski değer sessizce kaybolur |
| Sıralı ve Küme Yapıları | küme ekleme (`insert` → `bool`) | ifade | Sıra güvencesi bir koşula bağlıdır: anahtar tipinin sıralanabilirlik koşulunu karşılaması gerekir |
| Modüller ve Kasalar | `mod` bildirimi / `use` | öğe | Görünürlük yolun her halkasında ayrı sağlanır; bir öğe `pub` olsa bile onu saran modül değilse erişilemez |

Üç sınıf — ifade, deyim, öğe — kursun başından sonuna kadar değişmedi; değişen yalnızca bu
üç sınıfın uygulandığı yazımın genişliğiydi: tek bir satırdan bir fonksiyon gövdesine, bir
veri tipinin bildiriminden bir modülün sınırına. Sahiplik ve ödünç alma bu kursta defalarca
ertelendi — bir bağlamanın değişmezliği (Değişkenler ve Değişmezlik dersi), bir alıcının
`&self` işareti (Yapılar dersi), bir referansın çift `&` işareti (Koleksiyonlar dersi) her
seferinde bunun K02'nin konusu olduğu söylenerek geçildi. Sıradaki kurs bu ertelenen soruyu
açıyor: bir değerin sahibi kimdir, bir referans ödünç almak ne demektir ve bir değer
sahibinden ayrıldığında ne olur?

