---
title: 'İsteğe Bağlı Açma'
source: 'https://academia.sh/tr/kurslar/swift/istege-bagli-acma'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:13+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'if let ile guard let sağ tarafının bir kez ve hemen değerlendirildiğini ölçer'
    - '?? zincirinin ilk dolu adayda durduğunu ve sonrakini hiç değerlendirmediğini gösterir'
    - 'İsteğe bağlı zincirlemenin boş alıcıda argümanı da değerlendirmediğini ölçer'
    - 'Zorla açmanın neden bir yokluk kontrolünü yerinden çıkardığını açıklar'
---

# İsteğe Bağlı Açma

if let ve guard let sağ tarafının, ?? zincirinin ve isteğe bağlı zincirlemenin ne zaman değerlendirildiğinin ölçümü.

Önceki ders kutuyu açmadan çalıştı: `map` ve `flatMap` boş kutuda dönüştürücüyü hiç koşturmadı, dolu kutuda her çağrıda yeniden koşturdu. Sonuç yine bir kutuydu. Programın bir yerinde gerçek bir değere ihtiyaç duyulur: ekrana yazılacak bir sayı, bir dosyanın adı, bir toplamın terimi. Bu ders kutuyu açmanın yollarını sıralar ve her yol için aynı soruyu sorar: açılan ifade ne zaman değerlendiriliyor, açıldıktan sonraki kod ne zaman koşuyor?

Swift kutuyu açmak için birbirinden farklı araçlar sunar; bu ders beşini ölçer. **Koşullu bağlama (optional binding)**, yani `if let` ve `guard let`, kutuyu bir kez açar ve içindekini bir ada bağlar. `??` işleci boş kutu yerine bir yedek değer koyar. **İsteğe bağlı zincirleme (optional chaining)**, yani `?.`, bir çağrıyı yalnızca kutu doluysa yapar. Zorla açma, yani ünlem işaretiyle yazılan sonek işleç, yokluğu çalışma zamanında bir hataya çevirir. Beşincisi, `map` ve `flatMap`, önceki derste ölçüldü. Her aracın değerlendirme anı farklıdır ve fark hata yazılacak yeri belirler.

Kursun ölçü ekseni bu derste de aynıdır: **bu ifade ne zaman değerlendiriliyor?** Dört an vardır: hemen, ilk kullanımda, her kullanımda, hiç. Kuralı sayan `Probe` sınıfı aşağıda olduğu gibi verilir.

## Çekirdek

Her ders aynı çekirdeği kullanır. `Probe` bir ifadenin kaç kez değerlendirildiğini (`eval`) ve kaç kez kullanıldığını (`use`) sayar; `moment` özelliği bu iki sayıdan anı çıkarır. Açılış dersindeki bağlayıcı ölçümde sekiz ifadenin dağılımı 2/1/3/2 idi: ikisi hemen, biri ilk kullanımda, üçü her kullanımda, ikisi hiç. Bu derste yalnız kendi kesitini ölçeriz.

```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)")
    }
}
```

Ölçümlerde adı değiştirilebilen küçük bir sınıfa ihtiyaç var. Sınıfın kendisi bir ölçüm değildir, yalnızca zincirleme örneğine malzeme sağlar; bu yüzden çıktısı yoktur.

```swift
// User.swift — adi degistirilebilen kucuk bir sinif
final class User {
    var name: String
    var renames = 0

    init(name: String) {
        self.name = name
    }

    func rename(_ newName: String) {
        name = newName
        renames += 1
    }
}
```

## Koşullu Bağlama

`if let number = lookup("12", probe: source)` ifadesinde eşitliğin sağ tarafı bir isteğe bağlı değerdir. Swift bu ifadeyi bir kez değerlendirir, sonucu kontrol eder, kutu doluysa içindekini `number` adına bağlar ve blok gövdesini koşturur. Kutu boşsa gövde hiç çalışmaz. Aşağıdaki ölçümde sağ taraf `source.eval` ile sarılıdır ve bağlanan ad gövdede iki kez kullanılır.

```swift
// main.swift — if let sag tarafi bir kez degerlendirir, acilan ad iki kez kullanilir
let source = Probe("if-let-sag-taraf")

func lookup(_ text: String, probe: Probe) -> Int? {
    probe.eval(Int(text))
}

if let number = lookup("12", probe: source) {
    _ = source.use { number + 1 }
    _ = source.use { number * 2 }
}
source.report()
```

```
if-let-sag-taraf: 1 degerlendirme, 2 kullanim -> hemen
```

Bir değerlendirme, iki kullanım, an **hemen**. Sağ taraf bloğa girilmeden önce koştu; ad bağlandıktan sonra `number` sıradan bir tamsayıdır ve onu kullanmak sağ tarafı yeniden çalıştırmaz. Bu, önceki dersteki `map` ile bir tezat oluşturur: `map` dönüştürücüyü her çağrıda koşturuyordu, koşullu bağlama ise ifadeyi bir kez koşturup sonucu adda saklar. Aynı sağ tarafı sonradan iki kez okumak istediğimizde bağlanan ad ek bir değerlendirme gerektirmez.

Bağlanan ad yalnızca blok içinde geçerlidir; blok bittiğinde `number` yoktur. Aynı işlev çağrısını ikinci bir `if let` içinde yeniden yazmak ise ikinci bir değerlendirme demektir, çünkü `if let` sağ tarafını bağlama anında koşturur ve sonucu başka bir `if let` ile paylaşmaz. Değerin birden çok yerde gerekeceği durumda çağrıyı bir kez yazıp sonucu bir adda tutmak gerekir.

**TS5.** Bu ölçüm sağ tarafı tek bir işlev çağrısı olan `if let` için. Birden çok koşulun virgülle bağlandığı biçim (`if let a, let b`) ve `where` koşulu ölçülmedi.

## guard let ve Kısa Biçim

`guard let` aynı bağlamayı ters yönden yapar. Kutu boşsa `else` bloğu koşar ve bloğun kapsamı terk etmesi (`return`, `throw`, `break`, `continue` ya da `fatalError` gibi dönmeyen bir çağrı) zorunludur; kutu doluysa ad bağlanır ve bağlanan ad `guard` satırından sonra, işlevin kalan kısmında geçerlidir. Bu yüzden erken çıkış gerektiren kontroller `guard` ile yazılır: asıl iş girintisiz kalır, hata durumu en üstte toplanır. Kısa biçim olan `if let maybe` ise adı yeniden yazmadan aynı adla bağlar.

```swift
// main.swift — guard let ve kisa if let
func label(for text: String) -> String {
    guard let number = Int(text) else {
        return "gecersiz"
    }
    return "sayi \(number)"
}

let maybe: Int? = Int("5")
if let maybe {
    print("kisa bicim", maybe)
}
print(label(for: "30"))
print(label(for: "otuz"))
```

```
kisa bicim 5
sayi 30
gecersiz
```

Birinci satır kısa biçimi gösterir: `maybe` adlı isteğe bağlı değer, aynı adla ve isteğe bağlı olmayan bir tamsayı olarak blok içinde kullanılır. İkinci ve üçüncü satır `guard let` içeren `label(for:)` işlevinin iki yolunu gösterir: `"30"` bağlamayı geçer ve işlevin sonundaki dize oluşur, `"otuz"` ise `else` kolundan döner. Bağlanan `number` adı `guard` satırından sonra `Int` tipindedir; kutuyu bir daha açmaya gerek kalmaz.

İki bağlama biçimi arasındaki fark ağırlık dağılımındadır, yoksa ölçülebilen bir değerlendirme farkında değil. `if let` başarılı yolu bir blokta tutar, `guard let` hata yolunu bir blokta tutar. Hangi yol uzunsa onu girintisiz bırakan seçim daha okunur sonuç verir.

## Yedek Değer: ??

`??` işleci iki yandan oluşur. Soldaki isteğe bağlı değer doluysa içindeki değer sonuç olur; boşsa sağdaki yedek değer sonuç olur. Sağdaki ifade, **otomatik kapanış (autoclosure)** olarak yazılmış bir parametredir: Swift onu bir kapanışa sarar ve işleç yalnızca gerektiğinde çağırır. Bu, önceki dersteki dönüştürücünün bir başka örneğidir: kaynakta yazılı bir ifade, bir yöntem onu çağırana kadar hiç koşmayabilir.

Zincirleme yazıldığında bu davranış bir adım ileri gider. Aşağıda üç aday var: boş bir kutu, `second` probu ile işaretlenmiş dolu bir kutu ve `third` probu ile işaretlenmiş bir yedek sayı. Zincir ilk dolu adayda durur. Döngü iki tur döner ve her turda sonuç iki kez kullanılır.

```swift
// main.swift — ?? zinciri ilk dolu degerde durur
let second = Probe("ikinci-aday")
let third = Probe("ucuncu-aday")
let nothing: Int? = nil
let found: Int? = 8

for _ in 1...2 {
    let result = nothing ?? second.eval(found) ?? third.eval(0)
    _ = second.use { result }
    _ = third.use { result }
}
second.report()
third.report()
```

```
ikinci-aday: 2 degerlendirme, 2 kullanim -> her-kullanimda
ucuncu-aday: 0 degerlendirme, 2 kullanim -> hic
```

İkinci aday her turda değerlendirildi: iki tur, iki değerlendirme, an **her kullanımda**. Üçüncü aday hiç değerlendirilmedi, çünkü ikinci aday doluydu ve zincir orada kesildi. Yani `a ?? b ?? c` yazıldığında `c` yalnızca hem `a` hem `b` boşsa hesaplanır. Pahalı bir yedek değeri sağa koymak bu yüzden boşa iş üretmez: ilk aday dolu olduğu sürece o ifade hiç değerlendirilmez.

Bu davranışın bir yan sonucu vardır. Sağ taraftaki ifadenin yan etkisi, örneğin bir sayaç artırımı ya da bir günlük satırı, yalnızca soldaki kutu boşken gerçekleşir. Yan etkinin her durumda olmasını isteyen kod, yan etkiyi `??` ifadesinin içine değil, öncesine yazmalıdır.

**TS6.** Bu ölçüm üç adaylı bir zincir ve sabit dolu ikinci aday için. Soldaki kutunun dolu olduğu iki adaylı biçim ve yedek değerin bir işlev çağrısı olduğu durum ayrıca ölçülmedi.

## İsteğe Bağlı Zincirleme

`presentUser?.rename("y")` ifadesindeki `?` bir soru işaretidir ve bir yokluk kontrolünü işaretler. Alıcı doluysa çağrı yapılır; alıcı boşsa çağrı yapılmaz ve ifadenin değeri `nil` olur. Çağrının dönüş tipi `Int` olsaydı zincirleme onu `Int?` yapardı; bu yüzden zincirlemenin sonucu her zaman isteğe bağlı bir değerdir; dönüş tipi olmayan bir çağrıda bile sonuç `Void?` olur.

Asıl soru çağrının argümanıdır. `absentUser?.rename(skipped.eval("x"))` yazıldığında alıcı boştur ve çağrı yapılmaz. Argüman ifadesi çağrıdan önce hesaplanan bir şeydir; peki alıcı boşken de hesaplanır mı? İki alıcıyla ölçelim: biri boş, biri dolu. Her biri için argümanı `eval` ile işaretli bir probe ve döngü iki tur.

```swift
// main.swift — zincir nil'de durunca arguman da degerlendirilmez
let skipped = Probe("nil-alici")
let reached = Probe("dolu-alici")
let absentUser: User? = nil
let presentUser: User? = User(name: "ada")

for _ in 1...2 {
    absentUser?.rename(skipped.eval("x"))
    presentUser?.rename(reached.eval("y"))
    _ = skipped.use { absentUser?.renames }
    _ = reached.use { presentUser?.renames }
}
skipped.report()
reached.report()
print(presentUser?.name ?? "yok", presentUser?.renames ?? -1)
```

```
nil-alici: 0 degerlendirme, 2 kullanim -> hic
dolu-alici: 2 degerlendirme, 2 kullanim -> her-kullanimda
y 2
```

Boş alıcıda argüman hiç değerlendirilmedi. Zincirleme, alıcının boşluğunu gördüğü anda ifadenin geri kalanını atlar; argüman da bu "geri kalan"ın içindedir. Dolu alıcıda argüman her turda bir kez değerlendirildi. Son satır sonucu doğrular: dolu kullanıcının adı `y` oldu ve iki turda iki yeniden adlandırma sayıldı.

Bu davranışın uzun zincirlerde de sürmesi beklenir: `a?.b?.c(expensive())` yazıldığında `a` ya da `b` boşsa `expensive()` koşmamalıdır; bu ders yalnız iki halkalı zinciri ölçtü (TS8). Argümana yazılan yan etkili bir çağrıyı zincirin boş gelebilecek bir halkasının sağına koymak, o yan etkiyi koşullu yapar.

## Araçları Birleştirmek

Beş araç tek başına nadiren kullanılır. Yukarıdaki son çıktı satırı iki aracı birlikte gösterir: `presentUser?.name ?? "yok"` ifadesinde zincirleme kutuyu açıp adı okur, sonuç yine bir kutu olduğu için `??` boş kalan durumda bir yedek dize koyar. Alıcı dolu olduğundan çıktı `y` oldu; alıcı boş olsaydı `yok` yazılacaktı. Aynı şekilde `presentUser?.renames ?? -1` ifadesi sayaç değerini verir ve boş alıcıda `-1` döndürür.

Birleşimin değerlendirme anı bileşenlerinin anlarından çıkar. Zincirleme boş alıcıda geri kalanı atladığı için `??` yalnızca bir kez, zincirin döndürdüğü kutuya bakar. Yedek değer sağdadır ve soldaki dolu olduğu sürece hiç değerlendirilmez. Bu iki kural birbirini tamamlar: yokluk yalnızca bir yerde ele alınır ve ele alındığı noktadan sonra kod isteğe bağlı olmayan bir değerle çalışır.

**TS7.** Bu birleşim yalnız iki aracın yan yana olduğu durum için ve çıktıdaki son satırdan okundu. Üç ya da daha çok aracın iç içe yazıldığı biçimler ayrıca ölçülmedi.

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

Zincirleme için kurduğumuz kural şu: boş alıcıda argüman hiç değerlendirilmez. Önceki ölçümde alıcı doğrudan bir sabitti ve en baştan boştu. Peki yokluk zincirin ortasında, bir yöntem çağrısının sonucunda ortaya çıkarsa ne olur? Aşağıda `find` yöntemi her zaman `nil` döndürür. Bir ifade `find("ada")?.rename(...)` ile boş kutuya çağrı yapar; aynı satırdaki ikinci eleman ise zincirin parçası değil, ayrı bir ifadedir.

```swift
// main.swift — zincirin ortasinda bos donen halka, sonraki cagrinin argumanini atlatir
struct Directory {
    func find(_ name: String) -> User? {
        nil
    }
}

let tail = Probe("orta-bos-sonraki")
let free = Probe("orta-bos-bagimsiz")
let directory = Directory()

for _ in 1...2 {
    _ = (directory.find("ada")?.rename(tail.eval("z")), free.eval("w"))
    _ = tail.use { 0 }
    _ = free.use { 0 }
}
tail.report()
free.report()
```

```
orta-bos-sonraki: 0 degerlendirme, 2 kullanim -> hic
orta-bos-bagimsiz: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Zincirin ortasında doğan yokluk da sonraki çağrının argümanını atlattı: `find` boş döndüğünde `rename` çağrısı yapılmadı ve onun argümanı hiç değerlendirilmedi. Aynı satırda, virgülle ayrılmış ikinci elemandaki bağımsız ifade ise her turda değerlendirildi. Atlanan yer, `?` işaretinden sonra gelen zincirin kendisidir; aynı satırda yazılmış olmak bir ifadeyi zincirin parçası yapmaz.

Bu sonuç dersin kuralının geçerli olduğu alanı daraltır. "Boş alıcı argümanı değerlendirmez" cümlesi, zincirin boş kalan halkasından sonra gelen ifadeler için geçerlidir ve ölçülen iki halkada yokluğun nerede doğduğuna bağlı değildi. Zincirin dışındaki ifadeler bu kuralın kapsamına girmez.

**TS8.** Bu ölçüm iki halkalı bir zincir için. Üç ya da daha çok halkalı zincirlerde ortadaki bir `?` işaretinin davranışı ve alıcının bir özellik olduğu durum ayrıca ölçülmedi.

## Zorla Açma

Zorla açma işleci bu derste ölçülmez. Çünkü ölçülecek bir değerlendirme anı yoktur: kutu doluysa içindeki değer alınır, boşsa program durur. Aşağıdaki parça derlenir ama çalıştırıldığında çalışma zamanı hatası verir; çıktı iddiası taşımadığı için burada yalnız kaynak olarak durur.

```swift
let text = "otuz"
let broken = Int(text)!   // calisma zamaninda coker: kutu bos
print(broken)
```

Zorla açma, bir yokluk kontrolünü derleme zamanından çalışma zamanına taşır. Derleyicinin tip sistemiyle sağladığı güvence burada kalkar: `Int?` tipindeki değer, yazarın "bu kutu dolu" sözüne bağlı kalarak `Int` olarak kullanılır. Söz tutulmazsa program durur. Yokluğun kanıtlanmış biçimde imkânsız olduğu yerlerde, örneğin kaynak kodda sabit yazılmış ve geçerli olduğu bilinen bir metnin dönüştürülmesinde, zorla açma savunulabilir; kullanıcıdan ya da dışarıdan gelen veride savunulamaz.

## Özet

- `if let` sağ tarafı bir kez ve bloğa girmeden önce değerlendirir; bağlanan ad bir daha hesap yaptırmaz.
- `guard let` aynı bağlamayı erken çıkışla yazar; bağlanan ad `guard` satırından sonra geçerlidir.
- `??` zinciri ilk dolu adayda durur; sağdaki aday yalnızca soldaki boşsa hesaplanır.
- İsteğe bağlı zincirleme boş alıcıda `?` işaretinden sağdaki çağrıyı ve argümanını atlar.
- Zorla açma yokluk kontrolünü çalışma zamanına taşır ve ölçülecek bir an taşımaz.
- Bu dersin anı: **hemen**. `if let` sağ tarafı bloğa girmeden önce bir kez değerlendirilir.

## Sonraki Adım

Bu derste kutular açıldı ve içlerindeki değerler kullanıldı. Değerlerin kendisi iki yoldan biriyle tanımlanır: kopyalanan yapılarla ya da paylaşılan sınıflarla. Bir sonraki ders yapılar ve sınıflar arasındaki farkı, kopyanın tam olarak hangi anda oluştuğunu ölçerek inceler.
