---
title: 'İç Değişebilirlik'
source: 'https://academia.sh/tr/kurslar/sahiplik/ic-degisebilirlik'
course: 'Sahiplik ve Bellek Modeli'
language: tr
updated: '2026-10-21T05:03:44+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Aynı "bir yazan ya da çok okuyan" kuralının derleme yerine çalışma zamanında sınandığını koşturarak gösterir'
    - 'Bir bağlamanın kendisi değişmezken içindeki değerin RefCell ile değişebildiğini örnekle kanıtlar'
    - 'Başarısız bir ödünç denemesinin panik değil bool sonucuyla alınabildiğini gösterir'
---

# İç Değişebilirlik

Aynı 'bir yazan ya da çok okuyan' kuralının derleme zamanı yerine çalışma zamanında, bir sayaçla sınandığı ölçülüyor; bir bağlamanın kendisi değişmezken içindeki değerin RefCell ile değişebildiği ve başarısız bir ödünç denemesinin panik değil bool sonucuyla alınabildiği gösteriliyor. Kural kaybolmuyor, yer değiştiriyor.

Önceki üç ders boyunca paylaşılan bir değer hep okunabildi; `Rc` ve `Arc`ta hiç
değiştirilemedi, `Box`ta ise tek sahip olduğu için (bağlama `mut` alırsa) değiştirme zaten
mümkündü. Değişkenler ve Değişmezlik dersi de bir soru açık bırakmıştı: bir bağlamanın `mut`
almamasının, o bağlamanın **kendi adı üzerinden** hiçbir değişikliğe izin vermeyeceğini garanti
ettiği kurulmuştu, 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ğı sorusu bu kursa
(K02) bırakılmıştı. Bu ders tam o soruyu yanıtlıyor: bir değeri, sahiplik paylaşılırken de,
bağlama değişmez görünürken de değiştirmenin bir yolu var mı? Bu kursta ölçülen hep aynı
kalıyor — bir değerin nerede bittiği —, Eşzamanlılık kursunda (M09/K03) ölçülen koşan bir
birimin nasıl duracağı değil.

Yanıt evet, ama bu değişikliğin bir bedeli var; bu ders o bedeli ölçüyor ve bu konunun son
dersi olarak konunun dört ölçümünü de bir araya getiriyor.

Atomik Referans Sayımı dersi bu ihtiyacı açıkça bıraktı: `Arc` üzerinden bir alana
yazmaya çalışan bir satır derlenmiyordu, çünkü paylaşılan bir değere aynı anda kaç
kopyanın erişebileceğini bilmenin, o değeri güvenle değiştirmek için yeterli olmadığı
gösterilmişti. Aynı sınır `Rc` için de geçerliydi — `Box`ta tek sahip olduğu için
değiştirme zaten mümkündü (bağlama `mut` alırsa), ama `Rc` ve `Arc`ta paylaşım başladığı
andan itibaren yazma kapandı, çünkü ikisi de içerdikleri değere yalnızca paylaşımlı
erişim veriyordu. Bu derste o kapı yeniden açılıyor, ama farklı bir anahtarla: tipin
kendisinden değil, çalışma zamanında sınanan bir izinden geçerek.

## Kuralın Yer Değiştirmesi

Ödünç Denetleyicisi dersi, "aynı anda ya bir değiştirilebilir referans ya da birden çok
paylaşımlı referans" kuralının derleme zamanında sınandığını gösterdi: bu kuralı ihlal
eden bir yazım hiç derlenmiyordu. `RefCell<T>`, aynı kuralı **çalışma zamanına** taşıyan
bir kaptır. İçindeki değere `borrow()` ile paylaşımlı, `borrow_mut()` ile değiştirilebilir
erişim istenir; `RefCell` bu istekleri bir sayaçla izler ve kuralı ihlal eden bir istek
derlenmez değil, çalışma zamanında **reddedilir**.

Bu derste redd bir panikle değil, `try_borrow()` ve `try_borrow_mut()` çağrılarının
döndürdüğü bir sonuçla ölçülüyor: istek uygunsa `Ok`, değilse `Err`. Panik metni hiçbir
yerde basılmıyor; yalnızca isteğin başarılı olup olmadığı bir `bool` olarak yazdırılıyor.

`RefCell` de, tıpkı `Rc` ve `Arc` gibi, bir sayaç tutar — ama sayılan şey farklıdır. `Rc`
ve `Arc`ın sayacı kaç **sahibin** olduğunu sayıyordu ve sıfıra inince değer bitiyordu.
`RefCell`in sayacı kaç **aktif ödüncün** olduğunu sayar ve değeri hiç bitirmez; yalnızca
o an hangi tür erişimin (paylaşımlı mı, değiştirilebilir mi) sürdüğünü izler. Bu iki
sayaç birbirinden bağımsız çalışabilir: bir `Rc<RefCell<T>>` değeri hem kaç kopyasının
olduğunu hem de o an kimin onu ödünç aldığını, iki ayrı sayaçla aynı anda tutabilir. Bir
kopya bitip sahiplik sayacı azalırken, ödünç sayacı o kopyanın o an bir ödünç tutup
tutmadığından tamamen habersizdir — ikisi ayrı soruları yanıtlıyor.

## Bağlamanın Değişmezliği İçeriği Bağlamıyor

Aşağıdaki koşum bunu doğrudan gösteriyor: `sayac` adlı bağlama `mut` **değil**, ama
içindeki tam sayı yine de değişiyor.

**PS10.** — "bağlamanın kendisi değişmezken içindeki değerin değişebildiği" iddiası,
aşağıdaki koşumda `let sayac: RefCell<i64> = RefCell::new(0);` satırının `mut` içermemesine
rağmen `ilk yazimdan sonra deger: 1` satırının basılmasıyla doğrulanıyor.

```rust
// odunc_zaman_kaydirmasi.rs — derleme zamaninda reddedilen kural, calisma zamaninda bir sonuca donusuyor
use std::cell::RefCell;

fn main() {
    let sayac: RefCell<i64> = RefCell::new(0); // baglama mut degil

    {
        let mut yazan = sayac.borrow_mut();
        *yazan += 1;
    }
    println!("ilk yazimdan sonra deger: {}", sayac.borrow());

    let ilk_okuma = sayac.borrow();
    let ikinci_okuma = sayac.borrow();
    println!("iki okuma birlikte: {} ve {}", *ilk_okuma, *ikinci_okuma);

    let yazma_denemesi = sayac.try_borrow_mut();
    println!("okuma surerken yazma denemesi basarili mi: {}", yazma_denemesi.is_ok());

    drop(ilk_okuma);
    drop(ikinci_okuma);

    let ikinci_yazma_denemesi = sayac.try_borrow_mut();
    println!(
        "okumalar birakildiktan sonra yazma denemesi basarili mi: {}",
        ikinci_yazma_denemesi.is_ok()
    );
}
```

```
ilk yazimdan sonra deger: 1
iki okuma birlikte: 1 ve 1
okuma surerken yazma denemesi basarili mi: false
okumalar birakildiktan sonra yazma denemesi basarili mi: true
```

`sayac` bağlaması hiçbir yerde `mut` taşımıyor, ama `borrow_mut()` çağrısı içindeki değeri
gerçekten değiştiriyor. Değişkenler ve Değişmezlik dersi, `mut` almamanın **adın kendisi
üzerinden** hiçbir değişikliğe izin vermeyeceğini kurmuştu; `RefCell` bu garantiyi
bozmuyor — `sayac` adının kendisi hâlâ yeniden bağlanamıyor, hiçbir alanı sıradan bir
atamayla değiştirilemiyor. `borrow_mut()`, adın kendisinden değil, `RefCell`in çalışma
zamanında kontrol ettiği ayrı bir kapıdan giriyor. `ilk_okuma` ve `ikinci_okuma` aynı anda
yaşarken ikisi de aynı değeri okuyabiliyor — "çok okuyan" izinli. Onlar hâlâ yaşarken
gelen yazma denemesi başarısız oluyor; ikisi de bırakıldıktan sonra aynı deneme başarılı
oluyor. Kural aynı: bir yazan ya da çok okuyan, ikisi birden değil.

## İki Yazan da Aynı Kuralı İhlal Eder

Kural yalnızca "yazarken okunmasın" değil, "aynı anda iki yazan olmasın" kısmını da
kapsıyor. Aşağıdaki koşum bunu ayrıca sınıyor: bir değiştirilebilir ödünç sürerken ikinci
bir değiştirilebilir ödünç istendiğinde de aynı redd oluyor.

**PS11.** — "aynı anda iki değiştirilebilir ödüncün de reddedildiği" iddiası, aşağıdaki
koşumun `ilk yazan aktifken ikinci yazma denemesi basarili mi: false` satırıyla
doğrulanıyor.

```rust
// iki_yazici_denemesi.rs — ayni anda iki degistirilebilir odunc de reddediliyor
use std::cell::RefCell;

fn main() {
    let veri: RefCell<Vec<i32>> = RefCell::new(vec![1, 2, 3]);

    let mut ilk_yazan = veri.borrow_mut();
    ilk_yazan.push(4);

    let ikinci_yazma_denemesi = veri.try_borrow_mut();
    println!(
        "ilk yazan aktifken ikinci yazma denemesi basarili mi: {}",
        ikinci_yazma_denemesi.is_ok()
    );
    drop(ilk_yazan);

    let simdi_basarili_mi = veri.try_borrow_mut();
    println!("ilk yazan birakildiktan sonra basarili mi: {}", simdi_basarili_mi.is_ok());
    drop(simdi_basarili_mi);
    println!("veri uzunlugu: {}", veri.borrow().len());
}
```

```
ilk yazan aktifken ikinci yazma denemesi basarili mi: false
ilk yazan birakildiktan sonra basarili mi: true
veri uzunlugu: 4
```

`ilk_yazan` hâlâ elde tutulurken açılan ikinci deneme de reddediliyor — bu kez çakışan iki
okuma değil, iki yazma isteği. `ilk_yazan` üzerinden `veri`ye bir eleman eklenmiş olması
(`push(4)`), koruyucunun bırakıldığı anda kalıcı hâle geliyor: son satırdaki uzunluk dört.
Sayaç, kaç okuyucunun aktif olduğunu değil, aktif erişimin **türünü** de ayırt ediyor —
bir yazan varken ne başka bir yazan ne de bir okuyan kabul ediliyor.

Bu iki koşum (önceki bölümdeki ve bu bölümdeki) birlikte kuralın tamamını kapsıyor: çok
okuyan izinliyken, bir okuyanla bir yazan da, iki yazan da izinsizdi. Üç durumun ikisi
`try_borrow` ya da `try_borrow_mut`in `Err` döndürmesiyle, kalanı `Ok` döndürmesiyle
ölçüldü; hiçbirinde panik metni basılmadı, hiçbirinde program çökmedi. Ödünç
Denetleyicisi dersinde derleme zamanında reddedilen "okurken değiştirme" ihlali, burada
aynı adla, ama çalışma zamanında bir `Err` olarak karşımıza çıkıyor.

## Kural Kaybolmuyor, Yer Değiştiriyor

Ödünç Denetleyicisi dersindeki üç redd örneğinin hiçbiri kod bloğuna girmedi — hepsi
düzyazıda tarif edildi, yanlarına kabul edilen çözüm kondu; ihlal eden kaynak hiçbir zaman
derlenmedi. Burada aynı ihlal türü — bir değer yazılırken aynı değere başka bir erişim
istenmesi — gerçekten **derleniyor**; yalnızca çalışma zamanında `Err` üretiyor. Bu,
kuralın ortadan kalktığı anlamına gelmiyor: derleme zamanında kaçınılan bir hata, çalışma
zamanında bir sonuca dönüşüyor. Yukarıdaki koşumun `false` basan yazma denemesi satırı,
Ödünç Denetleyicisi dersinde hiç derlenmeyecek türden bir ihlalin burada derlendiğini ve
çalışma zamanında yakalandığını gösteriyor — program çökmüyor, çünkü redd
`try_borrow_mut` ile panik yerine bir `Result`e dönüştürülüyor.

Bu değiş tokuşun bedeli şudur: derleme zamanındaki denetim, bir yazımı çalıştırmadan önce
eler; çalışma zamanındaki denetim, aynı ihlali ancak o satır çalıştığında yakalar. Yanlış
kod artık derlenmiyor değil, çalışırken kendi başarısızlığını bildiriyor — ama bu bildirim
ancak o satıra gelindiğinde olur; ihlale hiç uğramayan bir çalıştırma, sorunu hiç
göstermez. Ödünç Denetleyicisi dersinde ölçülen "denetleyici doğruluğu değil, sahiplik
disiplinini güvence altına alır" ilkesi burada bir adım daha ileri gidiyor: çalışma
zamanı denetimi de yalnızca **çalışan yolu** sınıyor, kodun hiç uğramadığı bir satırdaki
ihlali göremiyor.

## Defterin Kendisi Bu Derste Açıklanıyor

Değişkenler ve Değişmezlik dersinin K02'ye bıraktığı soru tam olarak buydu: aynı veri
başka bir bağlama ya da referans üzerinden paylaşıldığında, değişmezlik oradan da geçerli
mi kalıyor? Bu kursun bütün derslerinde kullanılan `defter`, bu sorunun yanıtını baştan
beri örtük olarak taşıyordu. `defter`, `Rc<RefCell<Vec<String>>>` tipinde bir değerdi.
Referans Sayımı dersi `Rc` kısmını, bu ders `RefCell` kısmını açıklıyor: `defter`
paylaşılıyordu (`Rc`) ve içeriği değiştirilebiliyordu (`RefCell`) — iki kap iç içe
kullanılarak hem paylaşım hem değişebilirlik aynı anda sağlanıyordu.

**PS12.** — "bir işlevin `&Defter` alıp içeriği değiştirebildiği" iddiası, aşağıdaki
koşumda `kayit_ekle` işlevinin parametresinin `&Defter` olmasına (değiştirilebilir referans
değil) rağmen `kayit sayisi: 2` satırının basılmasıyla doğrulanıyor.

```rust
// defterin_ic_degisebilirligi.rs — bu kurs boyunca kullanilan defter tipi boyle calisiyordu
use std::cell::RefCell;
use std::rc::Rc;

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

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

fn kayit_ekle(defter: &Defter, metin: &str) {
    // defter parametresi & ile alindi, mut degil; yine de icerik degisiyor.
    defter.borrow_mut().push(metin.to_string());
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    kayit_ekle(&defter, "elle-eklenen");
    {
        let _olcum = Iz::yeni("birakildiginda-eklenen", &defter);
    }
    let kayit = defter.borrow();
    println!("kayitlar: {}", kayit.join(", "));
    println!("kayit sayisi: {}", kayit.len());
}
```

```
kayitlar: elle-eklenen, birakildiginda-eklenen
kayit sayisi: 2
```

`kayit_ekle` işlevi `defter: &Defter` alıyor — `&Rc<RefCell<Vec<String>>>`, yani sıradan
bir paylaşımlı referans. Buna rağmen `defter.borrow_mut().push(...)` çağrısı listeye
gerçekten bir eleman ekliyor. Bu, kursun ilk dersinden beri her `Iz::drop` çağrısının
yaptığı şeyin ta kendisidir: `drop` işlevi `&mut self` alsa bile, `self.defter` bir `Rc`
olduğu için doğrudan değiştirilemiyordu — `self.defter.borrow_mut().push(...)` satırı,
`&mut self`in kendi verdiği erişimi değil, `RefCell`in verdiği çalışma zamanı erişimini
kullanıyordu. Kursun başından beri koşan her koşum, aslında bu dersin ölçtüğü düzeneği
arka planda kullanıyordu — yalnızca bu ders o düzeneği açıkça adlandırıyor.

Bu, `defter`in neden `Vec<String>` değil de `Rc<RefCell<Vec<String>>>` olarak
tanımlandığını da açıklıyor. `Vec<String>` tek başına ne paylaşılabilir ne de birden
çok yerden değiştirilebilir olurdu — bir işlevin ya sahibi olması ya da ona sıradan bir
referans vermesi gerekirdi ve sıradan bir referansla `push` çağırmak `&mut` gerektirirdi.
`Rc` paylaşımı, `RefCell` değişebilirliği getirdi; ikisi birlikte, `Iz::yeni` her
çağrıldığında yalnızca `&Defter` geçirilmesine rağmen her `Iz` kendi bitişini aynı listeye
yazabildi. Kursun ilk üç dersi bu iç içe kabın yalnızca `Rc` yarısını konu etti; bu ders
öbür yarısını tamamlıyor.

## Erişim Şeffaf Değil, Açık Bir Çağrı Gerektiriyor

Öbekte Tekil Sahiplik dersi, bir `Box` içindeki alanlara doğrudan erişilebildiğini
gösterdi: `nokta.x` yazımı, değer öbekte olsa da olmasa da aynıydı. Atomik Referans Sayımı
dersinde de `paylasilan.deger` doğrudan okunabiliyordu. `RefCell` bu şeffaflığı
sürdürmüyor: içindeki değere doğrudan `hucre.alan` yazılarak erişilemez, önce `borrow()`
ya da `borrow_mut()` çağrılıp bir koruyucu değer alınması gerekir. Bu fark rastlantı
değil — `Box`, `Rc` ve `Arc` içindeki değere erişimin **her zaman güvenli** olduğunu
derleme zamanında biliyordu, bu yüzden erişimi gizleyebiliyordu. `RefCell` ise güvenliği
ancak çalışma zamanında, her çağrıda yeniden sınıyor; bu sınamanın kaynakta **görünür**
olması gerekiyor, çünkü sınama başarısız da olabilir.

Bu görünürlük, `try_borrow_mut`in döndürdüğü `Result` değerinde somutlaşıyor: bir `Box`
alanına yazmak asla başarısız olmayan bir işlemken, bir `RefCell`e yazmak denenip
**sonucu kontrol edilmesi gereken** bir işlemdir. Kod bu farkı gizleyemiyor — çağıran
taraf, isteğinin kabul edilip edilmediğini bir sonraki satırda ele almak zorunda kalıyor.
Bu, kursun üç ölçüm boyunca izlediği bir düzenin son adımıdır: bir işlemin ne zaman
kesin, ne zaman koşullu olduğu, o işlemin döndürdüğü tipten okunabiliyor — `()` her zaman
başarır, `Result` başarabilir ya da başarısız olabilir.

Dört ölçüm bir araya geldiğinde konunun bütün resmi ortaya çıkıyor. Öbekte Tekil Sahiplik,
bir değerin öbekte durabildiğini ama sahibinin tek kaldığını kurdu. Referans Sayımı, bu
tekliği sayılabilir bir çokluğa açtı. Atomik Referans Sayımı, bu sayımın farklı
bağlamlarda da aynı sonucu verdiğini, ama paylaşılan verinin hâlâ değiştirilemez
kaldığını gösterdi. Bu ders, o son kısıtı bir bedelle kaldırdı: değiştirme artık mümkün,
ama artık her deneme bir sonuç döndürüyor ve o sonucun kontrol edilmesi gerekiyor. Konu
boyunca hiçbir adımda belirlenimcilik kaybolmadı — her bitiş, her sayaç değişimi, her
ödünç denemesi, koşumda aynı sırayla, aynı sonuçla üretildi.

## Özet

- `RefCell<T>`, "bir yazan ya da çok okuyan" kuralını derleme zamanı yerine çalışma
  zamanında, bir sayaçla sınayan bir kaptır; içindeki değerin ömrü **kabıyla birlikte**
  bitiyor.
- Bir bağlamanın kendisi `mut` olmasa da, `RefCell` ile içindeki değer değişebilir; adın
  kendisi hâlâ yeniden bağlanamaz, değişim ayrı bir kapıdan geçer.
- Aynı veri birden çok bağlama (`Rc` kopyası) arasında paylaşıldığında da `RefCell` ile
  değiştirilebilir; bu, K01'in K02'ye bıraktığı "paylaşımda değişmezlik ne olur" sorusunu
  yanıtlar — kursun başından beri kullanılan `defter` tipi tam olarak bu düzenekti.
- Başarısız bir ödünç denemesi panikle değil, `try_borrow`/`try_borrow_mut`in döndürdüğü
  bir sonuçla ölçülür.
- Kural kaybolmaz, yer değiştirir: derleme zamanında kaçınılan bir ihlal, çalışma
  zamanında bir sonuca (`Err`) dönüşür.
- `RefCell` üzerinden erişim şeffaf değildir; her erişim açık bir `borrow` çağrısı
  gerektirir, çünkü çağrı her zaman başarılı olmayabilir.

## Sonraki Adım

Bu konunun dört dersi boyunca bir değerin sahipliği çoğaldı, sayıldı, atomikleşti ve en
sonunda paylaşılırken değiştirilebilir hâle geldi — ama her seferinde tek bir varsayım
hiç sorgulanmadı: paylaşan değerler birbirinden bağımsızdı, hiçbiri bir ötekini
**tutmuyordu**. Her sayaç, kendi değerine ait kalan kopyaları sayıyordu; hiçbir kopya,
sayılan değerin kendisini geriye doğru tutmuyordu. Kursun son sorusu tam bunu soruyor: ya
iki değer, `RefCell` üzerinden birbirinin içine birer `Rc` koyarak birbirini tutarsa?
Sayaç o zaman hâlâ sıfıra inebilir mi, yoksa hiç inemez mi?
