---
title: 'Sonuç Kurucular'
source: 'https://academia.sh/tr/kurslar/swift/sonuc-kurucular'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:12+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir dizgi listesi kuran kendi sonuç kurucusunu buildBlock ve buildExpression ile yazar'
    - 'Seçilmeyen if ve else dalındaki ifadelerin hiç değerlendirilmediğini ölçer'
    - 'for döngüsünün buildArray üzerinden her elemanı her çağrıda değerlendirdiğini gösterir'
    - 'Hangi dalın seçileceğinin derlemede değil koşumda belirlendiğini ayırt eder'
---

# Sonuç Kurucular

Kendi sonuç kurucumuzu yazar; seçilmeyen if ve else dalındaki ifadelerin hiç değerlendirilmediğini, for döngüsünün her elemanı değerlendirdiğini ve seçimin derlemede değil koşumda yapıldığını ölçer.

Önceki ders bir özelliğin değer kuralını ayrı bir tipe taşıdı. **Sonuç kurucu (`@resultBuilder`)** aynı fikri bir ifade listesine uygular. Bir kapanışın gövdesinde alt alta yazılan ifadeler normalde tek tek çalışır ve değerleri atılır. Sonuç kurucu ile işaretlenmiş bir parametreye verilen kapanışta ise her satır kurucu tipin bir yöntemine verilir ve yöntemlerin döndürdüğü değerler birleştirilerek tek bir sonuç elde edilir. Hangi satırın hangi anda çalışacağını, bu yöntemlerden hangisine nasıl bağlandığı belirler.

Bu ders bir dizgi listesi kuran küçük bir kurucu yazar ve üç şeyi ölçer: seçilmeyen `if` dalındaki ifadenin değerlendirilip değerlendirilmediğini, `for` döngüsünün elemanları nasıl işlediğini ve dalın seçiminin ne zaman yapıldığını. Dönüşümün kendisi derleme sırasında olur ve koşumda görülmez; ölçülen şey, dönüşmüş kodun koşum sırasındaki davranışıdır. Derleme ile koşum arasındaki bu ayrım önceki bir müfredatta ayrıca ele alınmıştı.

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

```swift
// ListBuilder.swift — dizgi listesi kuran sonuc kurucu
@resultBuilder
struct ListBuilder {
    static func buildExpression(_ line: String) -> [String] {
        [line]
    }

    static func buildBlock(_ parts: [String]...) -> [String] {
        parts.flatMap { $0 }
    }

    static func buildOptional(_ part: [String]?) -> [String] {
        part ?? []
    }

    static func buildEither(first part: [String]) -> [String] {
        part
    }

    static func buildEither(second part: [String]) -> [String] {
        part
    }

    static func buildArray(_ parts: [[String]]) -> [String] {
        parts.flatMap { $0 }
    }
}

func makeList(@ListBuilder _ content: () -> [String]) -> [String] {
    content()
}
```

## Kurucuyu Yazmak

`ListBuilder` altı statik yöntem taşır. `buildExpression` her tek ifadeyi bir dizgi listesine çevirir. `buildBlock` bir bloktaki parçaları art arda birleştirir. `buildOptional`, `else` dalı olmayan bir `if`'in sonucunu karşılar; dal seçilmediyse boş liste verir. `buildEither(first:)` ve `buildEither(second:)`, `if` ve `else` dallarından hangisi seçildiyse onu karşılar. `buildArray` bir `for` döngüsünün her yinelemesinden gelen parçaları birleştirir. `makeList` kapanışı `ListBuilder` ile işaretlenmiş bir parametre olarak alan yardımcı işlevdir.

## Seçilmeyen Dal Değerlendirilmez

İlk ölçüm `if`/`else` içinde iki ifade yazar. Biri `chosen` adlı `Probe`'u, öteki `skipped` adlı `Probe`'u çağırır. Koşul her zaman doğrudur, yani yalnız birinci dal seçilir. `render` işlevi iki kez çağrılır.

```swift
// main.swift — secilmeyen dalin ifadesi degerlendirilmez
let chosen = Probe("secilen-dal")
let skipped = Probe("secilmeyen-dal")

do {
    let useFirst = true

    func render() -> [String] {
        makeList {
            "baslik"
            if useFirst {
                chosen.eval("birinci")
            } else {
                skipped.eval("ikinci")
            }
        }
    }

    for _ in 1...2 {
        let lines = chosen.use { skipped.use { render() } }
        print(lines.joined(separator: ","))
    }
}

chosen.report()
skipped.report()
```

```
baslik,birinci
baslik,birinci
secilen-dal: 2 degerlendirme, 2 kullanim -> her-kullanimda
secilmeyen-dal: 0 degerlendirme, 2 kullanim -> hic
```

İki çağrıda da liste `baslik,birinci` olur. `secilen-dal` iki değerlendirme kaydeder, çünkü kurucunun gövdesi her `render` çağrısında yeniden çalışır. `secilmeyen-dal` ise iki kullanım görür ama sıfır değerlendirme: ikinci dalın ifadesi hiçbir zaman çalışmaz. Kural `hic` der. Bu dersin anı **hiç**tir: seçilmeyen dalın ifadesi hiçbir anda değerlendirilmez. İfadenin yalnızca yazılmış olması, onu çağırmaz.

## Döngü Her Elemanı Değerlendirir

`for` döngüsü `buildArray` ile birleştirilir ve gövdesindeki ifade her eleman için bir kez değerlendirilir. Ölçüm üç elemanlı bir diziyi iki kez işler ve aynı kapanışa `if` içeren bir satır da ekler; bu satır `buildOptional` yoluna girer.

```swift
// main.swift — for her elemani degerlendirir
let items = Probe("dongu-elemani")

do {
    func render(names: [String]) -> [String] {
        makeList {
            for name in names {
                items.eval(name)
            }
            if names.count > 2 {
                "uzun liste"
            }
        }
    }

    for _ in 1...2 {
        let lines = items.use { render(names: ["a", "b", "c"]) }
        print(lines.joined(separator: ","))
    }
}

items.report()
```

```
a,b,c,uzun liste
a,b,c,uzun liste
dongu-elemani: 6 degerlendirme, 2 kullanim -> her-kullanimda
```

Her çağrıda liste `a,b,c,uzun liste` olur. `dongu-elemani` altı değerlendirme kaydeder: iki çağrıda üçer eleman. Elemanlar bir kez önbelleğe alınmadı; kurucunun gövdesi her çağrıda baştan koşar ve döngü her elemanı baştan işler. Anı `her-kullanimda`dır. `if names.count > 2` satırının dizgisi bir `Probe`'dan geçmedi; yalnızca listede göründü.

## İfade Dönüşümü

`buildExpression`, bloktaki her tek ifadeyi kurucunun parça tipine çevirir. Aynı ada sahip birden çok `buildExpression` yazılırsa, derleyici ifadenin tipine uyanı seçer. Aşağıdaki `MixedBuilder` hem `String` hem `Int` kabul eder; sayıları `sayi 42` biçiminde bir dizgiye çevirir. Ölçüm iki ifadeyi ayrı `Probe`'lardan geçirir ve her çağrıda her ifadenin kaç kez değerlendirildiğine bakar.

```swift
// MixedBuilder.swift — metin ve sayi ifadesi kabul eden sonuc kurucu
@resultBuilder
struct MixedBuilder {
    static func buildExpression(_ line: String) -> [String] {
        [line]
    }

    static func buildExpression(_ number: Int) -> [String] {
        ["sayi \(number)"]
    }

    static func buildBlock(_ parts: [String]...) -> [String] {
        parts.flatMap { $0 }
    }
}

func makeMixed(@MixedBuilder _ content: () -> [String]) -> [String] {
    content()
}
```

```swift
// main.swift — buildExpression ifadeyi cevirir, yeniden degerlendirmez
let texts = Probe("metin-ifadesi")
let numbers = Probe("sayi-ifadesi")
do {
    for _ in 1...2 {
        let lines = texts.use {
            numbers.use {
                makeMixed {
                    texts.eval("baslik")
                    numbers.eval(42)
                }
            }
        }
        print(lines.joined(separator: ","))
    }
}
texts.report()
numbers.report()
```

```
baslik,sayi 42
baslik,sayi 42
metin-ifadesi: 2 degerlendirme, 2 kullanim -> her-kullanimda
sayi-ifadesi: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Çıktı iki çağrıda da `baslik,sayi 42` verir: dizgi ifadesi olduğu gibi geçti, tam sayı ifadesi `sayi 42` biçimine çevrildi. Çevirinin hangi yoldan yapıldığı ifadenin tipinden anlaşılır; kurucuya hiçbir ayırma yazılmadı. Sayaçlar dönüşümün değerlendirmeyi değiştirmediğini gösterir. `metin-ifadesi` ve `sayi-ifadesi` iki çağrıda ikişer değerlendirme kaydeder ve `her-kullanimda` der. `buildExpression` ifadenin sonucunu alır, ifadeyi yeniden çalıştırmaz. Kurucu kapanışın gövdesini çağrı başına bir kez baştan koşturur ve her ifade tam bir kez değerlendirilir. Bu yüzden dönüşüm yazarken yan etkili bir ifadenin tekrarlanacağından endişe edilmez. Aynı ad altında birden çok `buildExpression` yazmak, kurucunun kabul ettiği ifade tiplerini genişletir; tipi karşılamayan bir ifade ise derleme hatası verir, çalışma zamanında sessizce atlanmaz.

## İç İçe Koşul

`if` içindeki `if`, kurucuda iç içe iki `buildOptional` yolu açar. Dış koşul tutmazsa iç koşulun kendisi de değerlendirilmez. Ölçüm aynı kapanışı iki kez `visible: false` ile, sonra iki kez `visible: true` ile çalıştırır. İç koşul ve iç satırın ifadesi için her durumda ayrı birer `Probe` vardır.

```swift
// main.swift — dis kosul tutmazsa ic kosul degerlendirilmez
let closedGate = Probe("kapali-ic-kosul")
let closedHit = Probe("kapali-ic-satir")
let openGate = Probe("acik-ic-kosul")
let openHit = Probe("acik-ic-satir")
do {
    func render(visible: Bool, gate: Probe, hit: Probe) -> [String] {
        makeList {
            if visible {
                if gate.eval(true) {
                    hit.eval("ic")
                }
            }
        }
    }

    for _ in 1...2 {
        let shut = closedHit.use { closedGate.use { render(visible: false, gate: closedGate, hit: closedHit) } }
        let shown = openHit.use { openGate.use { render(visible: true, gate: openGate, hit: openHit) } }
        print("kapali \(shut.count), acik \(shown.count)")
    }
}
for probe in [closedGate, closedHit, openGate, openHit] {
    probe.report()
}
```

```
kapali 0, acik 1
kapali 0, acik 1
kapali-ic-kosul: 0 degerlendirme, 2 kullanim -> hic
kapali-ic-satir: 0 degerlendirme, 2 kullanim -> hic
acik-ic-kosul: 2 degerlendirme, 2 kullanim -> her-kullanimda
acik-ic-satir: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Dış koşul `false` iken ne iç koşul ne de iç satır değerlendirilir. `kapali-ic-kosul` ve `kapali-ic-satir` ikişer kullanıma karşılık sıfır değerlendirme kaydeder ve `hic` der; çıktıda `kapali 0` satırı da listenin boş kaldığını gösterir. Dış koşul `true` iken ise iki iç ifade de her çağrıda bir kez değerlendirilir: `acik-ic-kosul` ve `acik-ic-satir` ikişer değerlendirme kaydeder ve `her-kullanimda` der. `acik 1` satırı iç satırın listeye girdiğini doğrular. Koşulların sırası burada da kısa devre gibi davranır: sıradaki ifade yalnız öncekinin yolu açıksa değerlendirilir. Fark, bunun `&&` operatöründen değil, kurucunun `buildOptional` yolundan gelmesidir. Her `if` kendi `buildOptional` çağrısını üretir; dıştaki çağrının parçası boşsa içtekine hiç inilmez ve içteki ifade bu yüzden `hic` kalır.

## Boş Döngü

`buildArray`, döngünün her yinelemesinden gelen parçaları alır. Döngü hiç dönmezse parça listesi boştur ve `buildArray` boş bir liste üretir. Soru, boş bir dizi üzerinde kurulan döngünün gövdesindeki ifadenin değerlendirilip değerlendirilmediğidir. Ölçüm aynı kapanışı bir kez boş, bir kez dolu bir dizi ile çalıştırır.

```swift
// main.swift — bos dizi uzerinde dongu govdesi degerlendirilmez
let emptyLoop = Probe("bos-dongu")
let filledLoop = Probe("dolu-dongu")
do {
    func render(names: [String], probe: Probe) -> [String] {
        makeList {
            for name in names {
                probe.eval(name)
            }
        }
    }

    for _ in 1...2 {
        let none = emptyLoop.use { render(names: [], probe: emptyLoop) }
        let some = filledLoop.use { render(names: ["x", "y"], probe: filledLoop) }
        print("bos \(none.count), dolu \(some.count)")
    }
}
emptyLoop.report()
filledLoop.report()
```

```
bos 0, dolu 2
bos 0, dolu 2
bos-dongu: 0 degerlendirme, 2 kullanim -> hic
dolu-dongu: 4 degerlendirme, 2 kullanim -> her-kullanimda
```

Boş dizi üzerindeki döngüde gövdenin ifadesi hiç çalışmaz: `bos-dongu` iki kullanıma karşılık sıfır değerlendirme kaydeder ve `hic` der. `bos 0` satırı sonucun da boş liste olduğunu söyler; `buildArray` boş parça listesini boş bir sonuca çevirir ve hata vermez. Dolu dizide her çağrı iki eleman işler, dolayısıyla `dolu-dongu` iki çağrıda dört değerlendirme kaydeder ve `her-kullanimda` der. Değerlendirme sayısı döngünün dönüş sayısına eşittir. Kurucu gövdesinde döngü kuran biri için bu bir ölçüdür: elemanları yan etkili bir ifadeyle işleyen döngü, her çağrıda eleman sayısı kadar koşar. Koleksiyon çağrılar arasında saklanmaz; yan etkinin tekrarı gerekmiyorsa döngü kurucunun dışına alınır ve sonuç kurucuya hazır verilir.

Bu ölçümlerin ortak dersi şudur: kurucu, gövdedeki her satırı bir çağrıya çevirir ve hangi çağrının yapılacağını yazım biçimi belirler. Bir ifadenin değerlendirilip değerlendirilmeyeceğini okuyarak tahmin etmek yerine, dönüşümü zihinde açmak gerekir: ifade bir `buildExpression` çağrısına, koşul bir `buildOptional` (`else` varsa `buildEither`) çağrısına, döngü bir `buildArray` çağrısına dönüşür. Yan etkisi olan bir ifadeyi gövdeye koymadan önce bu çağrı zincirinde kaç kez ve hangi koşulda çalışacağı sorulur.

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

Dönüşüm derlemede yapılır, ama hangi dalın seçileceği koşumda belirlenir. Önceki iki ölçümde koşul sabitti ve bu fark görünmüyordu. Son ölçüm koşulu bir parametre yapar ve `render`'ı sırayla `true`, `false`, `true` ile çağırır. Her iki dalın ifadesi ayrı birer `Probe`'a yazılır.

```swift
// main.swift — dal secimi kosumda yapilir
let left = Probe("sol-dal")
let right = Probe("sag-dal")

do {
    func render(first: Bool) -> [String] {
        makeList {
            if first {
                left.eval("sol")
            } else {
                right.eval("sag")
            }
        }
    }

    for flag in [true, false, true] {
        let lines = left.use { right.use { render(first: flag) } }
        print(lines.joined(separator: ","))
    }
}

left.report()
right.report()
```

```
sol
sag
sol
sol-dal: 2 degerlendirme, 3 kullanim -> her-kullanimda
sag-dal: 1 degerlendirme, 3 kullanim -> ilk-kullanimda
```

Çağrılar sırasıyla `sol`, `sag`, `sol` yazar. `sol-dal` iki değerlendirme kaydeder: yalnız `true` ile gelen iki çağrıda koşar. `sag-dal` ise tek değerlendirme kaydeder ve bu değerlendirme ikinci çağrıda, yani ilk kullanımdan sonra olduğu için kural `ilk-kullanimda` der. İfade, dalın seçildiği çağrıda değerlendirilir; kodda yazılı olmasının tek başına bir anlamı yoktur. Bu yüzden `hic` anı yalnızca dal hiç seçilmediğinde geçerlidir ve koşula bağlıdır.

**BL5.** Ölçülen kurucu yalnız dizgi listesi kurar ve `buildLimitedAvailability` gibi ek yöntemler tanımlanmadı. İki dallı `if`, üç dallı `if`/`else if` zincirlerinde aynı kuralın geçtiği ölçülmedi. Tek bir kurucu tipinin kullanılması tasarım tercihidir.

## Özet

- Sonuç kurucu, kapanış gövdesindeki ifadeleri `buildBlock`, `buildExpression`, `buildOptional`, `buildEither` ve `buildArray` yöntemleriyle bir sonuca birleştirir.
- `if`/`else` içinde seçilmeyen dalın ifadesi hiç değerlendirilmez; yazılmış olması onu çağırmaz.
- Kurucunun gövdesi her çağrıda baştan koşar ve `for` döngüsü her elemanı her çağrıda değerlendirir.
- Dönüşüm derlemede yapılır, ama hangi dalın seçileceği koşumda belirlenir; `hic` anı yalnız dal hiç seçilmezse geçerlidir.
- Bu dersin anı: **hiç**. Seçilmeyen dalın ifadesi hiçbir anda değerlendirilmez.

## Sonraki Adım

Bu konunun ilk dersleri tek bir akışta çalışan koddaki bellek ve değerlendirme anlarını ölçtü. Birden çok iş aynı anda aynı belleğe dokunduğunda yeni sorular çıkar: bir değer kimin kontrolünde, kim ona ne zaman erişir. Sonraki ders aktörü, aktarılabilir tip anlamına gelen `Sendable`'ı ve `@MainActor`'ı anlatır; aktörün tembel özelliğinin ilk erişimde nasıl davrandığını ve `async let` ile başlatılan işi ölçer.
