---
title: Uzantılar
source: 'https://academia.sh/tr/kurslar/swift/uzantilar'
course: 'Swift Dili'
language: tr
updated: '2026-10-21T05:03:12+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Standart bir tipe uzantıyla yöntem ve hesaplanan özellik eklemek'
    - 'Uzantıyla bir tipe protokol uyumu kazandırmak ve `mutating` yöntem yazmak'
    - 'Uzantının saklanan örnek özelliği ekleyemeyeceğini, eklenen her özelliğin hesaplanan olduğunu açıklamak'
    - 'Uzantıdaki `static let` özelliğin ilk erişimde bir kez kurulduğunu ölçmek'
---

# Uzantılar

Var olan bir tipe dışarıdan yöntem, hesaplanan özellik ve protokol uyumu eklemeyi ölçer; saklanan özelliğin eklenemeyeceğini ve tip düzeyindeki istisnayı gösterir.

Önceki derste protokolün uzantısı, uyan her tipe bir varsayılan gövde verdi ve o gövde her okunuşta yeniden koştu. Aynı mekanizmanın somut hâli, bir tipi dışarıdan genişletmektir. `Int` ya da `String` gibi standart bir tipin kaynağına dokunamazsın, ama onun üzerine yeni bir yöntem yazabilirsin. Bu ders, uzantıyla eklenen şeyin ne zaman değerlendirildiğini soruyor.

**Uzantı (extension)**, var olan bir tipe, onun tanımını değiştirmeden yeni davranış ekler. Eklenebilenler: yöntemler, hesaplanan özellikler, alt simgeler, statik üyeler, başlatıcılar, iç içe tipler ve protokol uyumu. Eklenemeyen bir şey var, ve bu dersin ağırlığı onda: saklanan örnek özellik.

## Ölçüm Düzeneği

`Probe`, her derste aynı biçimde ilk blokta durur.

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

**TS27.** Uzantının gövdesi `Probe`'a parametre ya da eklenen tipin alanı olarak ulaşır; ölçümlerde bu iki yoldan biri seçildi, uzantıya küresel bir `Probe` bağlamak denenmedi.

## Eklenen Her Şey Hesaplanandır

Aşağıdaki blok üç tipe dört ekleme yapar. `Int`'e bir yöntem ve bir `mutating` yöntem, `String`'e bir yöntem eklenir. Kendi `Meter` tipimize ise bir hesaplanan özellik ve bir protokol uyumu eklenir: `CustomStringConvertible` uyumu, `description` özelliğini istediği için tipe bir metin gösterimi kazandırır.

```swift
// main.swift — uzantiyla eklenen her sey her kullanimda kosar
struct Meter {
    let value: Int
    let tracker: Probe
}

extension Int {
    func cubed(tracking tracker: Probe) -> Int { tracker.eval(self * self * self) }
    mutating func triple() { self *= 3 }
}

extension String {
    func padded(to width: Int, tracking tracker: Probe) -> String {
        tracker.eval(self + String(repeating: ".", count: max(0, width - count)))
    }
}

extension Meter {
    var centimeters: Int { tracker.eval(value * 100) }
}

extension Meter: CustomStringConvertible {
    var description: String { tracker.eval("\(value) m") }
}

let intMethod = Probe("int-yontemi")
let stringMethod = Probe("string-yontemi")
let computedExtra = Probe("eklenen-hesaplanan-ozellik")
let conformance = Probe("eklenen-uyum")

_ = intMethod.use { 3.cubed(tracking: intMethod) }
_ = intMethod.use { 4.cubed(tracking: intMethod) }

_ = stringMethod.use { "ab".padded(to: 5, tracking: stringMethod) }
_ = stringMethod.use { "ab".padded(to: 5, tracking: stringMethod) }

let meter = Meter(value: 7, tracker: computedExtra)
_ = computedExtra.use { meter.centimeters }
_ = computedExtra.use { meter.centimeters }

let described = Meter(value: 7, tracker: conformance)
_ = conformance.use { "\(described)" }
_ = conformance.use { "\(described)" }

var counter = 2
counter.triple()
counter.triple()
print(counter)

let all = [intMethod, stringMethod, computedExtra, conformance]
for probe in all { probe.report() }
tally(all)
```

```
18
int-yontemi: 2 degerlendirme, 2 kullanim -> her-kullanimda
string-yontemi: 2 degerlendirme, 2 kullanim -> her-kullanimda
eklenen-hesaplanan-ozellik: 2 degerlendirme, 2 kullanim -> her-kullanimda
eklenen-uyum: 2 degerlendirme, 2 kullanim -> her-kullanimda
hemen: 0
ilk-kullanimda: 0
her-kullanimda: 4
hic: 0
```

Dört eklemenin dördü de `her-kullanimda` çıktı. Yöntem her çağrıda koşar; bunu beklersin. Asıl dikkat edilecek olan `centimeters` özelliği: tip üzerinde bir alan gibi okunur ama saklanmaz, her okunuşta yeniden hesaplanır. `CustomStringConvertible` uyumu da aynı: `description` her metin enterpolasyonunda yeniden kurulur. `mutating` yöntem ise bir değeri yerinde değiştirir; `counter` iki üçleme sonunda 18 oldu. Bu değişiklik bir ifadenin değerlendirilmesi değil, bir değerin güncellenmesi olduğu için ayrı bir `Probe` gerektirmedi.

## Saklanan Özellik Eklenemez

Uzantıya bir saklanan örnek özellik yazmak istesen derleyici seni durdurur. Önce bunu doğruladık: aşağıdaki parça Swift 6.4'te derlenmedi, bu yüzden çıktısız kalıyor.

```swift
extension Meter {
    var unit = "m"
}
```

Gerekçe, bellek düzeninde. Bir tipin örneği, tanımındaki saklanan özelliklerin toplamı kadar yer kaplar; bu boyut tip tanımlandığında sabitlenir. Dışarıdan eklenen bir alan, bu boyutu tanımın dışında değiştirmek zorunda kalırdı; dilin kuralı bu yüzden saklanan örnek özelliği uzantıya kapatır. Bu yüzden uzantıyla eklediğin her özellik, tanım gereği, hesaplanan bir özelliktir: değer bir yerde durmaz, istendiğinde üretilir. Önceki bloğun hepsinin `her-kullanimda` çıkmasının nedeni budur. **TS28.** Bu bölümdeki red yalnız örnek düzeyindeki saklama için doğrulandı; `lazy` ya da gözlemleyen özelliği uzantıya eklemeyi ayrıca denemedik.

## Kısıtlı Uzantı

Bir uzantı her tipe değil, yalnız belirli bir koşulu sağlayan tiplere eklenebilir. `extension Array where Element: Numeric` yazdığında eklenen üyeler yalnız elemanları sayısal olan dizilerde görünür. **Kısıtlı uzantı (constrained extension)**, 06. derste protokol uzantısı için gördüğümüz `where` koşulunun tipler için olan hâlidir. Kısıt, eklemenin nereye uygulanacağını daraltır; eklenen gövdenin ne zaman koşacağını değiştirmez. Bunu aynı yöntemi iki farklı dizi tipinde çağırarak ölçüyoruz.

```swift
// main.swift — kisitli uzanti yalniz kosulu saglayan dizilere eklenir
extension Array where Element: Numeric {
    func total(tracking tracker: Probe) -> Element {
        tracker.eval(reduce(0, +))
    }
}

let intTotal = Probe("int-dizisi")
let doubleTotal = Probe("double-dizisi")

let counts = [1, 2, 3]
let weights = [0.5, 1.5]

_ = intTotal.use { counts.total(tracking: intTotal) }
_ = intTotal.use { counts.total(tracking: intTotal) }
_ = doubleTotal.use { weights.total(tracking: doubleTotal) }
_ = doubleTotal.use { weights.total(tracking: doubleTotal) }

let all = [intTotal, doubleTotal]
for probe in all { probe.report() }
```

```
int-dizisi: 2 degerlendirme, 2 kullanim -> her-kullanimda
double-dizisi: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Aynı gövde `Int` ve `Double` dizilerinde ayrı ayrı çalıştı ve ikisinde de her çağrıda koştu. Kısıt, `total` yönteminin bir `[String]` üzerinde görünmemesini sağlar; bu, derleme zamanında verilen bir karardır. Koşumda gördüğümüz tek şey, kısıtlı uzantının yöntemi sıradan bir yöntem gibi davrandığıdır: sonuç hiçbir yerde saklanmaz. **TS29.** Kısıtlı uzantının `[String]` üzerinde görünmediği ayrıca doğrulanmadı; burada yalnız kısıtı sağlayan iki tip ölçüldü.

## Uzantıda Başlatıcı ve İç İçe Tip

Uzantı bir tipe başlatıcı da ekleyebilir. Yapılarda bunun özel bir faydası vardır: başlatıcıyı tanım gövdesine yazarsan derleyicinin ürettiği üye bazlı başlatıcı (memberwise initializer) kaybolur; uzantıya yazarsan ikisi birlikte kalır. Uzantı ayrıca **iç içe tip (nested type)** ekleyebilir: başka bir tipin içinde tanımlanan, ona ait bir `enum`, `struct` ya da `class`. Aşağıdaki blok ikisini birlikte kullanır. Başlatıcı bir `Probe` değerlendirmesini kurulum anında yapar; iç içe tip ise çağrıldıkça koşan bir yöntem taşır.

```swift
// main.swift — uzantidaki baslatici ve ic ice tip
struct Length {
    let meters: Int
}

extension Length {
    init(centimeters: Int, tracking tracker: Probe) {
        self.init(meters: tracker.eval(centimeters / 100))
    }

    enum Unit {
        case meter, kilometer

        func factor(tracking tracker: Probe) -> Int {
            switch self {
            case .meter: tracker.eval(1)
            case .kilometer: tracker.eval(1000)
            }
        }
    }
}

let initProbe = Probe("uzantidaki-baslatici")
let nestedProbe = Probe("ic-ice-tip")

let direct = Length(meters: 5)
let converted = Length(centimeters: 700, tracking: initProbe)
_ = initProbe.use { converted.meters }
_ = initProbe.use { converted.meters }
print(direct.meters)

_ = nestedProbe.use { Length.Unit.kilometer.factor(tracking: nestedProbe) }
_ = nestedProbe.use { Length.Unit.kilometer.factor(tracking: nestedProbe) }

let all = [initProbe, nestedProbe]
for probe in all { probe.report() }
```

```
5
uzantidaki-baslatici: 1 degerlendirme, 2 kullanim -> hemen
ic-ice-tip: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

`Length(meters:)` üye bazlı başlatıcısı, uzantıdaki başlatıcıya rağmen kullanılabilir kaldı; ikisi yan yana durdu. Uzantıdaki başlatıcıda değerlendirme kurulum anında, bir kez yapıldı ve sonuç `meters` alanında saklandı; alanı iki kez okumak yeni bir değerlendirme üretmedi: `hemen`. Bu, eklenen özelliklerin her okunuşta koşmasıyla bir çelişki değildir. Başlatıcı bir özellik eklemez, var olan saklanan alanı doldurur; saklama tanımdaki `meters` alanındadır. İç içe tipin yöntemi ise sıradan bir yöntem gibi her çağrıda koştu: `her-kullanimda`. **TS30.** İç içe tip burada bir `enum` olarak ölçüldü; uzantıdan eklenen iç içe `struct` ya da `class` ayrıca denenmedi.

## Uzantıda Alt Simge

Uzantı yalnız yöntem ve hesaplanan özellik değil, **alt simge (subscript)** de ekleyebilir. Alt simge, bir değeri `değer[indeks]` biçiminde okumayı sağlayan üyedir ve gövdesi bir hesaplanan özelliğin okuyucusu gibi çalışır. Aşağıda `Array`'e sınır dışı indekste çökmeyen bir okuma ekliyoruz. Alt simge fazladan parametre alabilir; ölçüm düzeneğimizi buradan geçiriyoruz.

```swift
// main.swift — uzantidaki alt simge her okumada kosar
extension Array {
    subscript(safe index: Int, tracking tracker: Probe) -> Element? {
        let found: Element? = indices.contains(index) ? self[index] : nil
        return tracker.eval(found)
    }
}

let subscriptProbe = Probe("alt-simge")
let names = ["a", "b", "c"]

_ = subscriptProbe.use { names[safe: 1, tracking: subscriptProbe] }
_ = subscriptProbe.use { names[safe: 9, tracking: subscriptProbe] }

subscriptProbe.report()
```

```
alt-simge: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

İki okuma iki değerlendirme verdi; sınır dışı indeks de gövdeyi çalıştırdı ve yalnız sonuç `nil` oldu. Alt simge, bir özellik gibi görünse de saklama yapmaz: her `[...]` ifadesi gövdeyi yeniden koşturur, `her-kullanimda`. Bu, "Eklenen Her Şey Hesaplanandır" bölümündeki kuralın alt simgeye de uzandığını gösterir. **TS31.** Burada yalnız okuma yapan bir alt simge ölçüldü; yazan (`set`) alt simge denenmedi.

## Uzantıda Değiştiren Yöntem

Değer tiplerinde (yapı ve enum) bir yöntem, `self`'i değiştiriyorsa `mutating` ile işaretlenir. Uzantıdaki yöntem de aynı kurala uyar; bir uzantı, tanımda olmayan bir `mutating` yöntem ekleyebilir. Değiştirilen şey tanımdaki saklanan alandır, yani uzantı saklama eklemeden var olan saklamayı kullanır.

```swift
// main.swift — uzantidaki mutating yontem
struct Counter {
    var count = 0
}

extension Counter {
    mutating func bump(tracking tracker: Probe) {
        count += tracker.eval(1)
    }
}

let bumpProbe = Probe("mutating-yontem")
var counter = Counter()

bumpProbe.use { counter.bump(tracking: bumpProbe) }
bumpProbe.use { counter.bump(tracking: bumpProbe) }

print(counter.count)
bumpProbe.report()
```

```
2
mutating-yontem: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Alan iki çağrıda iki artış aldı ve değer `counter.count` içinde kaldı; uzantı yöntemin kendisini ekledi, saklamayı eklemedi. Gövde her çağrıda yeniden koştu: `her-kullanimda`. Önceki bölümlerle birleştirince tablo şöyle çıkar: uzantı ne eklerse eklesin, ister özellik, ister alt simge, ister yöntem olsun, eklenen gövde her kullanımda koşar. Başlatıcı bu tablonun dışında kalır, çünkü o bir okuma değil bir kurulum adımıdır. **TS32.** `mutating` yöntem yalnız yapı üzerinde ölçüldü; sınıf ya da enum için ayrıca doğrulanmadı.

## Uzantıda Statik Üye

Tipe ait, bir değerle değil tipin kendisiyle çağrılan üyeler **statik üye**dir (`static`). Uzantı bunları da ekleyebilir. Özellikler dersinde bir `static let` gördük ve o, ilk erişimde bir kez kuruluyordu. Statik bir yöntem ise sıradan bir yöntemdir; ayrım, yöntemle özellik arasındaki ayrımdır. Aşağıdaki uzantı `Length`'e tipin kendisinden çağrılan bir üretici ekler ve ölçer.

```swift
// main.swift — uzantidaki static yontem
struct Length {
    let meters: Int
}

extension Length {
    static func fromKilometers(_ kilometers: Int, tracking tracker: Probe) -> Length {
        Length(meters: tracker.eval(kilometers * 1000))
    }
}

let staticProbe = Probe("static-yontem")
_ = staticProbe.use { Length.fromKilometers(2, tracking: staticProbe) }
_ = staticProbe.use { Length.fromKilometers(3, tracking: staticProbe) }

staticProbe.report()
```

```
static-yontem: 2 degerlendirme, 2 kullanim -> her-kullanimda
```

Statik yöntem her çağrıda koştu: `her-kullanimda`. Bir tipe ait olması gövdesini önbelleğe almaz; bu ölçümde önbellekleme yalnız `static let` gibi saklanan bir statik özellikte görüldü. Demek ki uzantıya ne yazdığın, hesaplanan mı saklanan mı olduğuna bağlıdır, ve uzantı saklanan özelliği zaten yasaklar. Statik saklanan özellik bu yasağa takılmaz, çünkü saklama örnekte değil tipin kendisindedir. **TS33.** Statik yöntemin sonucu burada her seferinde yeni bir `Length` üretti; bir örnek eşitliği ya da kimliği ölçülmedi.

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

Yasak yalnız örnek düzeyindedir. Uzantı, tipe bir `static let` ekleyebilir, çünkü tip başına tek bir kopya vardır ve bellek düzenini etkilemez. Bu özelliğin ne zaman kurulduğunu `print` ile gözlüyoruz. `Probe` burada kullanılamaz: `Probe` `Sendable` değildir ve Swift 6 dil kipinde küresel ya da tip düzeyindeki `let` özellik `Sendable` bir tip ister. Kurulumun içindeki `print` satırı, kurulumun kaç kez ve hangi sırada koştuğunu gösteren sayaçtır.

```swift
// main.swift — uzantidaki static let ilk erisimde bir kez kurulur
struct Scale {
    let factor: Int
}

extension Scale {
    static let unit: Int = {
        print("unit kuruldu")
        return 100
    }()
}

print("erisimden once")
print(Scale.unit)
print(Scale(factor: 3).factor * Scale.unit)
print(Scale.unit)
```

```
erisimden once
unit kuruldu
100
300
100
```

`unit kuruldu` satırı bir kez çıktı ve ilk erişimin hemen önünde. Eklenen `static let`, tip düzeyinde `ilk-kullanimda` anını verir: ilk okumaya kadar bekler, bir kez kurulur, sonra saklanır. Böylece uzantıda örnek düzeyinde yasak olan saklama, tip düzeyinde izinli ve tembeldir. Eklenen örnek özellikler `her-kullanimda`, eklenen tip özelliği `ilk-kullanimda` ölçüldü; ikisi aynı uzantıda yan yana durabilir. **TS34.** Bu gözlem `print` sırasına dayanır; ilk erişimin eşzamanlı iki yerden gelmesi durumunda kurulumun bir kez koştuğu burada ölçülmedi.

## Özet

- Uzantı, var olan bir tipe tanımını değiştirmeden yöntem, hesaplanan özellik, başlatıcı ve protokol uyumu ekler.
- `Int` ve `String` gibi standart tiplere de yöntem eklenir; `mutating` yöntem değeri yerinde günceller.
- Uzantı saklanan örnek özellik ekleyemez; eklenen her özellik hesaplanandır ve her okunuşta yeniden koşar.
- Uzantıdaki `static let` istisnadır: tip düzeyinde, ilk erişimde bir kez kurulur.
- Bu dersin anı: **her kullanımda** (uzantıyla eklenen hesaplanan özellik ve yöntem).

## Sonraki Adım

Uzantı bir tipe davranış ekledi, ama eklenen davranış tek bir tipe bağlıydı. `Int` için yazdığın `cubed`, `Double` için yeniden yazılmak zorunda. Sıradaki ders, aynı gövdeyi birçok tip için bir kez yazmayı sağlayan genelliklere geçiyor.
