---
title: 'Sabitler ve Değişkenler'
source: 'https://academia.sh/tr/kurslar/swift/sabitler-ve-degiskenler'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:11+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - '`let` ile `var` arasındaki farkı atama davranışı üzerinden açıklamak'
    - 'Tip çıkarımı ile açık tip bildirimini karşılaştırmak'
    - 'Ertelenmiş başlatmanın ve yeniden atamanın değerlendirme anını yorumlamak'
    - 'Başka dosyadaki küresel sabitin ilk erişimde kurulduğunu sıralama çıktısından okumak'
---

# Sabitler ve Değişkenler

`let` ve `var` ile tip çıkarımını, açık tip bildirimini ve atama anını ölçer: sabit hemen mi değerlendirilir, atama her seferinde mi?

Önceki derste bir `let` sabitinin tanımlandığı satırda `hemen` değerlendirildiğini gördün. Bu ders o gözlemi üç yönden zorluyor: sabite tip yazmak bir şeyi değiştirir mi, `var` her atamada ne yapar, ve değer tanımlandıktan sonra atanırsa an kayar mı? Değişken ve tip kavramlarını Programlama Temelleri kursundan (M01/K02) biliyorsun; burada yalnız Swift'e özgü kısmı ölçüyoruz.

## Sabit, Değişken ve Tip

Swift'te `let` bir kez bağlanan sabiti, `var` sonradan değişebilen değişkeni tanımlar. Tipi çoğu zaman yazmazsın: derleyici sağ taraftan çıkarır (tip çıkarımı, type inference). İstersen tipi iki noktadan sonra yazarsın (açık tip bildirimi, explicit type annotation). Sabite ikinci kez atama yapmak derleyicide reddedilir: aşağıdaki parça Swift 6.4'te derlenmez, bu yüzden çıktısızdır.

```swift
let rate = 4
rate = 5
```

`var` için aynı atama serbesttir. Fark yalnız yazım değil: `var` satırı her atamada sağ tarafı yeniden değerlendirir.

## Üç Atama Biçimi

Önce `Probe.swift` yardımcı dosyası; her derste aynı kalır.

```swift
// Probe.swift — bir ifadenin ne zaman degerlendirildigini kaydeder
final class Probe {
    let label: String
    private(set) var evaluations = 0
    private(set) var uses = 0
    private var evaluatedBeforeUse = false

    init(_ label: String) {
        self.label = label
    }

    func eval<T>(_ value: T) -> T {
        evaluations += 1
        if uses == 0 { evaluatedBeforeUse = true }
        return value
    }

    func use<T>(_ access: () -> T) -> T {
        uses += 1
        return access()
    }

    var moment: String {
        if evaluations == 0 { return "hic" }
        if evaluations > 1 { return "her-kullanimda" }
        return evaluatedBeforeUse ? "hemen" : "ilk-kullanimda"
    }

    func report() {
        print("\(label): \(evaluations) degerlendirme, \(uses) kullanim -> \(moment)")
    }
}

func tally(_ probes: [Probe]) {
    for moment in ["hemen", "ilk-kullanimda", "her-kullanimda", "hic"] {
        let count = probes.filter { $0.moment == moment }.count
        print("\(moment): \(count)")
    }
}
```

Şimdi üç `Probe`: biri tipi çıkarılan sabiti, biri tanımı ile ataması ayrılmış sabiti, biri de üç kez atanan değişkeni izler.

```swift
// main.swift — sabit ve degisken atama anlari
let inferredProbe = Probe("cikarilan-sabit")
let deferredProbe = Probe("ertelenen-sabit")
let counterProbe = Probe("degisken-atamasi")

let rate = inferredProbe.eval(4)
let explicitRate: Double = 4
_ = inferredProbe.use { rate }
_ = inferredProbe.use { rate }
print("\(type(of: rate)) \(type(of: explicitRate))")

let isWeekend = false
let level: Int
if isWeekend {
    level = deferredProbe.eval(1)
} else {
    level = deferredProbe.eval(2)
}
_ = deferredProbe.use { level }
_ = deferredProbe.use { level }

var total = counterProbe.eval(0)
total = counterProbe.eval(total + 5)
total = counterProbe.eval(total + 7)
_ = counterProbe.use { total }
_ = counterProbe.use { total }

let allProbes = [inferredProbe, deferredProbe, counterProbe]
for probe in allProbes { probe.report() }
tally(allProbes)
```

```
Int Double
cikarilan-sabit: 1 degerlendirme, 2 kullanim -> hemen
ertelenen-sabit: 1 degerlendirme, 2 kullanim -> hemen
degisken-atamasi: 3 degerlendirme, 2 kullanim -> her-kullanimda
hemen: 2
ilk-kullanimda: 0
her-kullanimda: 1
hic: 0
```

İlk satır tipleri gösterir: tipi yazılmayan `4` bir `Int`, `Double` olarak bildirilen aynı sayı bir `Double` oldu. Tip çıkarımı değerlendirme anını değiştirmedi; çıkarılan sabit tanımlandığı satırda, ilk kullanımdan önce değerlendirildi, yani `hemen`.

`level` ilginç bir durumdur: tanım (`let level: Int`) ile değer arasına bir `if` girdi, ama atama kullanımdan önce yapıldı. Dalların ikisi de `eval` çağırır, çalışan ise biri; sayı bir, an yine `hemen`. Derleyici atamadan önce okumayı reddeder (önceki dersin ilk parçası), bu yüzden tanım ile atama arasında okuma olamaz; ama atama bir kullanım sarmalının içinde yapılırsa ölçüm `ilk-kullanimda` verir (aşağıdaki Ertelenmiş İlk Değer bölümü).

`var` ise başka. `total` üç kez atandı ve her atama sağ tarafı yeniden değerlendirdi; kural bunu `her-kullanimda` okur. Değişken tek kez bağlanan bir sabit değildir; her atama yeni bir değerlendirmedir.

**DT8.** `counterProbe` atamaları kullanımdan önce yapılır, ama üç değerlendirme olduğu için kural `her-kullanimda` der; sayı birden çoksa "önce mi sonra mı" bakılmaz.

**DT9.** `type(of:)` çıktısı yalnız `Int` ve `Double` adlarını basar; tip adı ölçüm eksenine değil, çıkarımın sonucuna işaret eder.

## Tip Çıkarımı ve Açık Tip Bildirimi

Bir sabit ya da değişken tanımlarken tipi yazmak zorunda değilsin. `let attempts = 3` satırında derleyici sağdaki değişmezden `Int` çıkarır; buna tip çıkarımı (type inference) denir. İstersen tipi iki noktadan sonra açıkça yazarsın: `let ratio: Double = 3`. Buna açık tip bildirimi (explicit type annotation) denir. İkisinin farkı yalnız tipi kimin belirlediğidir: çıkarımda değerden tip, açık bildirimde tipten değer biçimi türer.

Fark en çok değişmez bir sayı yazdığında görünür. `3` değişmezi çıkarımda `Int` olur, ama sol tarafa `Double` yazarsan aynı değişmez `3.0` olarak okunur. Aşağıdaki blok aynı `3` değişmezini iki yolla bağlar, her ikisini bir `Probe`'dan geçirir ve iki kez okur.

```swift
// Literal.swift — ayni degismez, iki tip
let inferredProbe = Probe("cikarilan-int")
let declaredProbe = Probe("acik-double")
let attempts = inferredProbe.eval(3)
let ratio: Double = declaredProbe.eval(3)
_ = inferredProbe.use { attempts }
_ = inferredProbe.use { attempts }
_ = declaredProbe.use { ratio }
_ = declaredProbe.use { ratio }
print(attempts, ratio)
print(type(of: attempts), type(of: ratio))
inferredProbe.report()
declaredProbe.report()
```

```
3 3.0
Int Double
cikarilan-int: 1 degerlendirme, 2 kullanim -> hemen
acik-double: 1 degerlendirme, 2 kullanim -> hemen
```

`attempts` `3` olarak, `ratio` ise `3.0` olarak yazıldı; `type(of:)` satırı tiplerin `Int` ve `Double` olduğunu doğruluyor. Değişmezin yazılışı aynıydı, ama bağlamdan gelen tip onu iki farklı değere çevirdi. İki `Probe` ise aynı anı verdi: ikisi de `hemen`. Tip yalnız değerin ne olduğunu belirler, ne zaman değerlendirileceğini belirlemez. Derleyici tipi kodu çalıştırmadan bulur; çalışma sırasında geriye kalan yalnız tek bir `eval` çağrısıdır.

Bu yüzden açık tip bildirimi iki iş görür. Birincisi, çıkarımın seçeceğinden farklı bir tip istediğinde onu söylemektir. İkincisi, kodu okuyana değerin niyetini göstermektir. Ölçüm ekseni açısından ise ikisi eşittir.

**DT10.** Çıkarım ve bildirim aynı `3` değişmeziyle ölçüldü; daha karmaşık bir ifadede tipin ne kadar erken bulunduğu bu dersin dışındadır.

## Demet Çözümleme ve Tek Satırda Çok Tanım

Swift bir sabit ya da değişken satırında birden çok ad tanımlamana izin verir. Virgülle ayırarak `var left = 0, right = 0` yazabilirsin; her ad kendi ifadesiyle ayrı ayrı bağlanır. Başka bir yol, bir demeti açmaktır: `let (low, high) = (1, 9)` iki sabit tanımlar ve demetin elemanlarını sırayla onlara dağıtır. Bu söz dizimi demet çözümleme (tuple decomposition) olarak anılır.

Aklına gelen soru şudur: iki ad aynı satırda tanımlandığında ifadeleri aynı anda mı değerlendirilir, yoksa biri öbüründen önce mi? Aşağıdaki blok iki ayrı `Probe` ile iki adı bir demetle tanımlar, ardından iki `var` adı tek satırda tanımlayıp sırayla atar.

```swift
// Decompose.swift — demet cozumleme ve tek satirda cok tanim
let lowProbe = Probe("alt-sinir")
let highProbe = Probe("ust-sinir")
let (low, high) = (lowProbe.eval(1), highProbe.eval(9))
_ = lowProbe.use { low }
_ = lowProbe.use { low + 1 }
_ = highProbe.use { high }
_ = highProbe.use { high - 1 }
var left = 0, right = 0
left = lowProbe.eval(low)
right = highProbe.eval(high)
_ = lowProbe.use { left }
_ = highProbe.use { right }
print(low, high, left, right)
lowProbe.report()
highProbe.report()
```

```
1 9 1 9
alt-sinir: 2 degerlendirme, 3 kullanim -> her-kullanimda
ust-sinir: 2 degerlendirme, 3 kullanim -> her-kullanimda
```

Demetin iki elemanı da tanım satırında, hiçbir okumadan önce değerlendirildi. Ama bu bir tek değerlendirme değildi: `lowProbe` ve `highProbe` birer değerlendirme gösterdi, sonra `left` ve `right` atamaları ikinci birer değerlendirme ekledi. Bu yüzden iki ölçüm satırı da iki değerlendirme, üç kullanım ve `her-kullanimda` verdi. Tek satırda tanım ya da demet çözümleme, ifadeleri tek bir adımda birleştirmez; her eleman kendi ifadesi kadar değerlendirilir.

Burada ilke şudur: bir ifadenin kaç kez değerlendirildiğini, onu kaç satırda yazdığın değil, `eval` benzeri kaç değerlendirme noktası olduğu belirler. Demet çözümlemesi yazımı kısaltır, çalışma sırasını değiştirmez.

**DT11.** Demet çözümleme iki elemanlı ve sabit değişmezle ölçüldü; iç içe demetlerin çözülme sırası bu dersin dışındadır.

## Gölgeleme

Bir iç kapsamda dış kapsamla aynı adı yeniden tanımlayabilirsin. Buna gölgeleme (shadowing) denir: iç kapsamdaki ad, dış kapsamdakini kapsam bitene kadar görünmez kılar. Dış değişken ya da sabit hiçbir şekilde değişmez; yalnız iç kapsamdaki okumalar yeni ada gider. Bu davranış, bir değeri geçici olarak dönüştürüp aynı adı kullanmanın güvenli yoludur.

Gölgeleme yeni bir atama değildir. `amount` ikinci kez `let` ile tanımlandığında dış `amount` olduğu gibi kalır; yeni tanım ikinci bir değerlendirmedir ve yalnız kendi kapsamında yaşar. Aşağıdaki blok bir `do` kapsamı içinde dış `amount` sabitini gölgeler, iç değeri yazdırır, kapsamdan çıkar ve dış değeri yeniden yazdırır.

```swift
// Shadow.swift — golgeleme dis degeri degistirmez
let outerProbe = Probe("dis-kapsam")
let innerProbe = Probe("ic-kapsam")
let amount = outerProbe.eval(1)
do {
    let amount = innerProbe.eval(amount + 10)
    _ = innerProbe.use { amount }
    _ = innerProbe.use { amount * 2 }
    print(amount)
}
_ = outerProbe.use { amount }
_ = outerProbe.use { amount + 5 }
print(amount)
outerProbe.report()
innerProbe.report()
```

```
11
1
dis-kapsam: 1 degerlendirme, 2 kullanim -> hemen
ic-kapsam: 1 degerlendirme, 2 kullanim -> hemen
```

İç kapsamda `amount` 11 çıktı: iç tanımın sağ tarafındaki `amount` hâlâ dış sabitti, çünkü iç ad henüz bağlanmamıştı. Kapsamdan çıkınca `amount` yeniden 1 oldu; gölgeleme dış sabiti hiç değiştirmedi. İki `Probe` ayrı ayrı bir değerlendirme ve iki kullanım gösterdi: ikisi de `hemen`. Gölgeleme yeni bir değerlendirme ekler, ama bir yeniden atama olmadığı için dış tarafın sayısını artırmaz.

Pratikte gölgeleme, değişken adlarını çoğaltmadan bir değeri dönüştürmenin sade yoludur. Karşılığında okuyanın hangi `amount` ile karşılaştığını bilmesi gerekir; kapsamı kısa tutmak bu yükü azaltır.

**DT12.** Gölgeleme `do` kapsamıyla ölçüldü; fonksiyon parametresini ya da döngü değişkenini gölgelemenin davranışı bu dersin dışındadır.

## Ertelenmiş İlk Değer

Bir `let` sabitine tanımlandığı satırda değer vermek zorunda değilsin. Tipini yazıp değeri sonra atayabilirsin, yeter ki derleyici her yolda sabite tam olarak bir kez değer verildiğini görebilsin. Bu kural, `let` bildiriminin "değişmez" anlamını korur: sabit ilk değerini alana kadar okunamaz, aldıktan sonra yeniden atanamaz. Dallanan bir akışta her dal sabiti bir kez doldurur ve sabit, dalın sonunda hazırdır.

Bunun ölçülecek bir yan etkisi vardır: yalnız seçilen dalın ifadesi çalışır. Aşağıdaki blok bir fonksiyon yazar. Fonksiyonda `label` sabiti önce bildirilir, sonra `if` ile bir dalda `Probe`'dan gelen değerle, öbür dalda sabit bir dizgiyle doldurulur. Fonksiyon önce `true`, sonra `false` ile çağrılır.

```swift
// Deferred.swift — ertelenmis ilk deger
func pick(open: Bool, probe: Probe) -> String {
    let label: String
    if open {
        label = probe.eval("acik")
    } else {
        label = "kapali"
    }
    return label
}
let pickProbe = Probe("ertelenmis-sabit")
print(pickProbe.use { pick(open: true, probe: pickProbe) })
print(pickProbe.use { pick(open: false, probe: pickProbe) })
pickProbe.report()
```

```
acik
kapali
ertelenmis-sabit: 1 degerlendirme, 2 kullanim -> ilk-kullanimda
```

`true` çağrısı `acik`, `false` çağrısı `kapali` verdi. Her çağrıda yeni bir `label` sabiti tanımlandığı ve her biri bir kez doldurulduğu için derleyici bunu kabul etti. `Probe` ise iki kullanıma karşılık tek değerlendirme gösterdi: `probe.eval` yalnız `true` dalında çalıştı, `false` dalının sabit dizgisi `Probe`'a hiç uğramadı. İlk kullanımda değerlendirilen ve sonra bir daha çalışmayan bir ifade, `ilk-kullanimda` anının işaretidir; burada ikinci çağrı o ifadeye hiç ulaşmadı.

Bu davranış, ertelenmiş ilk değerin bir kural olduğunu gösterir: her yol sabiti tam olarak bir kez doldurur, doldurmayan yol hiçbir şey hesaplamaz. Sabitin değeri, akış hangi dala girerse onun ifadesinden gelir. Derleyici bir dalda atamayı unutursan, sabiti o noktadan sonra kullanmana izin vermez.

Bu kural bir fonksiyonun dönüş değerini hazırlarken de işe yarar: sabit bildirilir, dallar onu doldurur ve fonksiyon sonunda tek bir `return` kalır. Yerine `var` kullanıp sonradan değiştirmek de çalışırdı, ama `let` derleyiciye ve okuyana değerin bir kez atandığını söyler.

**DT13.** Ertelenmiş ilk değer iki dalla ve bir fonksiyon içinde ölçüldü; üst düzey kodda ya da özelliklerde aynı yapının kuralları bu dersin dışındadır.

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

Bir sabitin `hemen` değerlendirilmesi her yerde geçerli değildir. Başka dosyada tanımlı bir küresel sabit, ilk erişimde kurulur. Aşağıdaki yardımcı dosya başlatma kapanışına bir `print` koyar; kapanış `let` tanımının içindedir.

```swift
// Config.swift — baska dosyadaki kuresel sabit
let appName: String = {
    print("appName kuruluyor")
    return "academia"
}()
```

`main.swift` ise aynı kalıpta bir yerel sabit tanımlar ve iki sabitin ne zaman kurulduğunu satır sırasıyla gösterir.

```swift
// main.swift — kuresel ve yerel sabitin kurulus ani
print("baslangic")
let localName: String = {
    print("localName kuruluyor")
    return "academia"
}()
print("ikinci satir")
print("okunan: \(appName)")
print("yerel: \(localName)")
```

```
baslangic
localName kuruluyor
ikinci satir
appName kuruluyor
okunan: academia
yerel: academia
```

`localName` `main.swift` üst düzeyinde, yazıldığı satırda kuruldu (`hemen`); `appName` ise ikinci satırdan sonra, ilk okunduğu `print` içinde kuruldu (`ilk-kullanimda`). Aynı yazılışın iki farklı anı vardır.

**DT14.** `Probe` bu gözleme giremez: `Probe` `Sendable` değildir ve Swift 6 kurallarında küresel sabit olarak tutulamaz; bu yüzden an burada `print` sırasından okunur, sayıdan değil.

**DT15.** Bu ölçüm yalnız bir küresel sabit ve yalnız bir yardımcı dosya içindir; sıralama kuralının başka durumlarını (örneğin birden çok küresel sabitin birbirine bağlı kurulması) ölçmüyoruz.

## Özet

- `let` bir kez bağlanır, ikinci atama derleyicide reddedilir; `var` yeniden atanabilir.
- Tip çıkarımı ile açık tip bildirimi değerlendirme anını değiştirmez.
- Ertelenmiş başlatma yalnız atamadan sonra okunabilir; atama kullanımdan önceyse `hemen`, bir kullanım sarmalının içindeyse `ilk-kullanimda` verir.
- Her `var` ataması sağ tarafı yeniden değerlendirir; kural bunu `her-kullanimda` okur.
- Bu dersin anı: **hemen** (tanımlandığı ya da atandığı satırda değerlendirilen sabit).

## Sonraki Adım

Sabitlerin ve değişkenlerin atama anını ölçtük. Bir sonraki ders, üzerlerine konan değerlerin tiplerine bakıyor: `Int`, `Double`, `Bool` ve `String` arasındaki dönüşüm ne zaman yapılıyor?
