---
title: Değişkenler
source: 'https://academia.sh/tr/kurslar/kotlin/degiskenler'
course: 'Kotlin Dili'
language: tr
updated: '2026-10-21T05:02:40+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - '`val` ile `var` arasındaki farkı ve yeniden atamanın ne zaman reddedildiğini söylemek'
    - 'Tip çıkarımının neyi bulduğunu ve açık tip yazmanın ne zaman gerektiğini açıklamak'
    - 'Aynı sabitten gelen iki değişkenin aynı nesneye işaret ettiğini, çalışma anında kurulan değerin ise içerik ölçütüne düştüğünü göstermek'
---

# Değişkenler

`val` ve `var` ile bildirimi, tip çıkarımını ve `const val` sabitini tanıtır; aynı dizgi sabitinin iki değişkende tek nesne olduğunu ölçer.

Önceki derste eşitliğin dört ölçütünü sekiz değer üzerinde gördük. Bu derste değerin bir ada bağlanışına bakıyoruz: `val` ve `var` ile bildirilen değişkenler. Soru şudur: aynı sabiti iki ayrı değişkene bağlarsam iki ayrı nesne mi oluşur, yoksa tek nesneye iki ad mı verilmiş olur?

## val, var ve Tip Çıkarımı

Kotlin'de bir değişkeni `val` ya da `var` ile bildirirsiniz. `val` yeniden atanamayan değişkendir (read-only): ilk değer verildikten sonra aynı ada başka bir değer atanamaz. `var` ise yeniden atanabilir. İki biçim de değer verirken tipi yazmak zorunda bırakmaz; derleyici sağdaki ifadeden tipi bulur. Bu çıkarım (type inference) derleme zamanında olur ve değişkenin tipi sonradan sabit kalır. Tipi açıkça yazmak isterseniz ad ile değer arasına iki nokta ve tip koyarsınız.

`val` ile bildirilen bir değişkenin bağlı olduğu nesnenin hiç değişmediğini düşünmek yanlış olur: `val` yalnız adın bir daha başka değere bağlanamayacağını söyler. Bağlandığı nesne içinden değişebiliyorsa o değişebilir. Bu ayrım ilerleyen derslerde işe yarayacak; burada yalnız adın yeniden atanıp atanamadığına bakıyoruz.

Bu derste de ölçümler ilk derste tanıtılan yardımcı dosyayla yapılır. `Criterion` sınıfı, bir değer ile ikizini ve farklı bir değeri alıp üç soruyu sorar; dosya aşağıda aynen verilmiştir.

```kotlin
// Criterion.kt — iki degeri esit yapan olcutu siniflandirir
class Criterion(val label: String, first: Any?, twin: Any?, other: Any?) {
    val sameObject = first === twin
    val equalTwin = first == twin
    val equalOther = first == other

    val name: String = when {
        sameObject -> "tekil"
        !equalTwin -> "kimlik"
        !equalOther -> "icerik"
        else -> "kismi-icerik"
    }

    fun report() {
        println("$label: ayni-nesne=$sameObject, ikiz=$equalTwin, farkli=$equalOther -> $name")
    }
}

fun summarize(checks: List<Criterion>) {
    for (name in listOf("tekil", "kimlik", "icerik", "kismi-icerik")) {
        println("$name: ${checks.count { it.name == name }}")
    }
}
```

Aşağıdaki program bildirimin dört yüzünü bir arada gösterir. `city` yeniden atanamaz, `visits` yeniden atanır, `ratio` tipini açıkça yazar, `inferred` ise tipini çıkarımdan alır. Dosyanın tepesindeki `const val` ise derleme zamanı sabitidir (compile-time constant): değeri derleme sırasında bilinen ve yalnız temel tip ya da dizgi olabilen ve üst düzeyde ya da bir nesne bildirimi içinde duran bir sabit.

```kotlin
// Main.kt — val, var, tip cikarimi ve const val
const val MAX_VISITS = 3

fun main() {
    val city = "Ankara"
    var visits = 1
    visits = visits + 1
    val ratio: Double = 2.0
    val inferred = 7
    println("$city, ziyaret: $visits, oran: $ratio")
    println("cikarilan tip: ${inferred::class.simpleName}")
    println("ust sinir: $MAX_VISITS")
}
```

```
Ankara, ziyaret: 2, oran: 2.0
cikarilan tip: Int
ust sinir: 3
```

Çıktıda `Ankara, ziyaret: 2, oran: 2.0` satırı `visits` değişkeninin bir kez yeniden atandığını gösterir. `cikarilan tip: Int` satırı, `7` sabitinden çıkarılan tipin `Int` olduğunu doğrular; bunu `inferred::class.simpleName` ile çalışma anında sorduk. Son satır `const val` sabitinin değerini basar. Aynı çıktı sandbox'ta Kotlin 2.4.21 ile alındı.

**DT8.** Çıkarılan tip yalnız `7` sabitiyle ölçüldü; `Long` ya da `Double` gerektiren bağlamlarda çıkarımın ne yaptığı bir sonraki dersin konusudur.

**DT9.** `const val` yalnız dosyanın tepesinde ölçüldü; bir `object` ya da `companion object` içindeki hâlinin kuralları bu dersin dışındadır.

Bu çıktıdan çıkan pratik sonuç şudur. `visits` gibi bir sayaç `var` ister, çünkü değeri programın akışında değişir. `city` gibi bir ad ise `val` ister, çünkü ilk atamadan sonra başka değere bağlanması bir hata olurdu. Karar değişkenin rolüne göre verilir; tipin çıkarımla mı yazıldığı bu kararı etkilemez.

## Yeniden Atama Reddedilir

`val` ile bildirilen bir değişkene ikinci kez değer atamak derleyicide reddedilir. Bunu sandbox'ta derleyerek gördük; aşağıdaki parça bu yüzden çıktısızdır ve bir `main` taşımaz.

```kotlin
val limit = 10
limit = 20
```

Derleyici ikinci satırı `val` yeniden atanamaz diyerek reddeder, program hiç çalışmaz. Bu, yeniden atamayı çalışma anının değil derleme zamanının sorunu yapar. Kotlin'de varsayılan tercih `val` olur; `var` yalnız değerin gerçekten yeniden atanması gerektiğinde yazılır. Böylece bir ada bakan okuyucu, o adın bir yerde başka değere bağlanıp bağlanmadığını aramak zorunda kalmaz.

**DT10.** Reddedilme tek bir yerel `val` ile ölçüldü; üst düzey `val` ve sınıf özelliği olan `val` için hata mesajının biçimi bu derste doğrulanmadı.

## Aynı Sabit, İki Değişken

Şimdi dersin ölçümü. Dört gözlem var. `val-literal`: iki ayrı `val`, aynı `"kotlin"` sabitine bağlanır. `var-literal`: bir `var` ile aynı sabit karşılaştırılır. `val-kurulan` ve `var-kurulan` ise aynı metni çalışma anında kurar; biri `joinToString` ile, öbürü `buildString` ile. Bildirim biçimi `val` ya da `var` olsa da fark etmeyip etmediğini böylece ölçeriz.

Her gözlemde `Criterion` üç şey alır: ölçülen değer, aynı biçimde kurulmuş bir ikiz ve farklı bir değer. Sabit gözlemlerinde ikiz ikinci bir değişkendir ya da doğrudan sabitin kendisidir. Kurulan gözlemlerde ikiz, aynı yöntem bir kez daha çağrılarak üretilir; böylece iki taraf da çalışma anında ayrı ayrı oluşur. Farklı değer her seferinde bir harfi değiştirilmiş `kotlim` dizgisidir.

```kotlin
// Main.kt — ayni literal iki degiskende
fun main() {
    val first = "kotlin"
    val twin = "kotlin"
    var changeable = "kotlin"
    val built = listOf("kot", "lin").joinToString("")
    var builtVar = buildString {
        append("kot")
        append("lin")
    }
    val checks = listOf(
        Criterion("val-literal", first, twin, "kotlim"),
        Criterion("var-literal", changeable, "kotlin", "kotlim"),
        Criterion("val-kurulan", built, listOf("kot", "lin").joinToString(""), "kotlim"),
        Criterion("var-kurulan", builtVar, buildString {
            append("kot")
            append("lin")
        }, "kotlim"),
    )
    for (check in checks) {
        check.report()
    }
    summarize(checks)
}
```

```
val-literal: ayni-nesne=true, ikiz=true, farkli=false -> tekil
var-literal: ayni-nesne=true, ikiz=true, farkli=false -> tekil
val-kurulan: ayni-nesne=false, ikiz=true, farkli=false -> icerik
var-kurulan: ayni-nesne=false, ikiz=true, farkli=false -> icerik
tekil: 2
kimlik: 0
icerik: 2
kismi-icerik: 0
```

`val-literal` tekildir: `first` ile `twin` aynı nesnedir, `ayni-nesne=true`. Aynı dizgi sabiti, derleme sırasında tek bir nesne olarak tutulur ve onu kullanan her ifade aynı nesneye ulaşır. `var-literal` de tekildir; `var` kullanmak sabitin aynı nesne olmasını bozmaz, çünkü `var` yalnız adın yeniden atanabilirliğini etkiler. `val-kurulan` ile `var-kurulan` ise içeriktir: `joinToString` ve `buildString` çalışma anında yeni bir dizgi üretir, bu yüzden `ayni-nesne=false`; ikizle `==` yine `true` verir, farklı değerle `false`.

Özet satırlarında iki tekil, iki içerik görünür. Yani bir değeri `val` ile ya da `var` ile bağlamak ölçütü belirlemez; ölçütü belirleyen, değerin nereden geldiğidir: sabit mi, çalışma anında kurulmuş bir değer mi.

**DT11.** Dizgi sabitinin tek nesne olması Kotlin 2.4.21'in JVM hedefinde ölçüldü; bu davranış JVM'in dizgi havuzuna dayanır ve başka hedeflerde aynı olduğu iddia edilmiyor.

**DT12.** Kurulan dizgiler `joinToString` ve `buildString` ile ölçüldü; ikisi dışındaki kurma yollarının aynı sonucu verdiği bu derste ölçülmedi.

## val Bağlanan Nesneyi Dondurmaz

Yukarıda `val` için "ad bir daha başka değere bağlanamaz" demiştik. Bu cümlenin sınırı, bağlanan nesnenin kendisinin değişebilmesidir. Aşağıdaki blok `val` ile bildirilmiş bir değişebilir liste kurar ve ona eleman ekler. Ardından ilk değeri bildirim satırında verilmeyen, sonradan atanan bir `val` gösterir.

```kotlin
// Main.kt — val bagli nesneyi degistirebilir, ilk deger sonra verilebilir
fun main() {
    val names = mutableListOf("ada")
    names.add("can")
    println(names)
    val assigned: Int
    val flag = names.size > 1
    if (flag) {
        assigned = 10
    } else {
        assigned = 20
    }
    println(assigned)
}
```

```
[ada, can]
10
```

`names` bir `val`dir; yine de `add` çağrısı listeyi `[ada, can]` hâline getirir. Hata veren bir şey yoktur, çünkü `names` adı hâlâ aynı listeye bağlıdır; değişen listenin içidir. İkinci değişken `assigned` bildirim satırında değer almaz, tipi yazılıdır ve `if` ile `else` dallarının her birinde tam bir kez atanır. Derleyici bu deseni kabul eder ve ekrana `10` basar. Kural şudur: `val` değişken, kapsamının her yolunda en çok bir kez değer alabilir.

Sık yapılan hata, `val` sözcüğünü "nesne değiştirilemez" diye okumaktır. Bir listenin içeriğini dondurmak istiyorsanız salt okunur bir koleksiyon tipi seçilir (`listOf`); `val` tek başına bunu sağlamaz. Java karşılaştırması: Java'daki `final` değişken aynı sınırı taşır, `final` bir listeye eleman eklenebilir ve ilk değerin sonradan verildiği `final` değişken de Java'da bilinen bir desendir. Bu iki Java davranışı burada ölçülmedi, bilinen davranış olarak anıldı.

**DT13.** Bu bölümde `MutableList` ve `Int` ile ölçüldü; `val` bir `data class` örneğine bağlıysa özelliklerinin değişip değişmediği bu derste ölçülmedi.

## Lambda İçinden var Değiştirmek

Kotlin, bir lambdanın kendi dışındaki `var` değişkenini okumasına ve değiştirmesine izin verir. Aşağıdaki blok bir toplamı ve bir çağrı sayacını `forEach` içinden günceller; ardından toplamın o andaki değerini bir `val` içine kopyalayıp asıl `var` değişkenini değiştirir.

```kotlin
// Main.kt — lambda icinden var degistirmek
fun main() {
    var total = 0
    var calls = 0
    listOf(1, 2, 3).forEach {
        total += it
        calls++
    }
    println("toplam: $total, cagri: $calls")
    val snapshot = total
    total = 100
    println("kopya: $snapshot, var: $total")
}
```

```
toplam: 6, cagri: 3
kopya: 6, var: 100
```

Birinci satır `toplam: 6, cagri: 3` verir: lambda üç kez çalıştı ve dışarıdaki iki değişken de güncellendi. İkinci satır kopyanın ayrı kaldığını gösterir. `snapshot` değeri `6` olarak kalır, `total` ise `100` olur. `Int` değeri atandığı anda kopyalandığı için sonradan değişen `var` kopyaya yansımaz.

Mekanizmanın nedeni lambdanın dışarıdaki değişkeni değer olarak değil, o değişkenin kendisini taşıyarak yakalamasıdır; lambda ve dış kod aynı `var` üzerinde çalışır. Java'da aynı iş için lambdanın yakaladığı yerel değişkenin etkin olarak `final` olması gerekir, bu yüzden sayaç tutmak için dizi ya da `AtomicInteger` gibi bir kap kullanılır. Kotlin'de böyle bir geçici çözüme gerek yoktur. Bu Java kuralı ve Kotlin'in arkada yakalanan değişkeni nasıl taşıdığı bu derste ölçülmedi; ölçülen yalnız dışarıdaki `var` değerlerinin lambda sonrasında güncel olduğudur.

**DT14.** Yakalanan değişken `Int` tipindeydi ve `forEach` ile ölçüldü; çok iş parçacıklı bir bağlamda aynı güncellemenin davranışı bu dersin dışındadır.

## const val ve Birleşim

Dersin başında `const val` için "değeri derleme sırasında bilinen sabit" dedik. Bu tanımın bir sonucu var: iki `const val` dizgisinin birleşimi de derleme sırasında hesaplanır. Aşağıdaki blok iki `const val` birleşimini, aynı metni çalışma anında `joinToString` ile kuran bir üst düzey `val` ile karşılaştırır. İkizi her iki ölçümde aynı ifadenin bir kez daha yazılmasıyla gelir.

```kotlin
// Main.kt — const val birlesimi ve calisma ani degeri
const val PREFIX = "kot"
const val FULL = PREFIX + "lin"

val runtimeFull = listOf("kot", "lin").joinToString("")

fun main() {
    val checks = listOf(
        Criterion("const-birlesim", FULL, "kotlin", "kotlim"),
        Criterion("calisma-ani-top-level", runtimeFull, "kotlin", "kotlim"),
    )
    for (check in checks) {
        check.report()
    }
    summarize(checks)
}
```

```
const-birlesim: ayni-nesne=true, ikiz=true, farkli=false -> tekil
calisma-ani-top-level: ayni-nesne=false, ikiz=true, farkli=false -> icerik
tekil: 1
kimlik: 0
icerik: 1
kismi-icerik: 0
```

`const-birlesim` tekildir: `PREFIX + "lin"` ifadesi derleme zamanında `"kotlin"` sabitine dönüşür ve dizgi havuzundaki tek nesneye bağlanır. `calisma-ani-top-level` içeriktir: aynı metin çalışma anında kurulduğunda ayrı bir dizgi olur, `ayni-nesne=false`. Özet satırında bir tekil ve bir içerik görünür.

Burada sık yapılan hata, `const val` ile üst düzey `val` değişkenini birbirinin yerine kullanılabilir saymaktır. İkisi de dosyanın tepesinde durur ve ikisi de yeniden atanamaz; ama biri değerini derleme sırasında, öbürü program çalışırken alır. Sınır durumu da buradan çıkar: `const val` yalnız derleyicinin hesaplayabildiği değerlerle kurulur. Java karşılaştırması: Java'daki `static final` alan benzer bir ayrımı taşır, derleme zamanı sabiti olan ve olmayan `static final` alanlar vardır. Bu Java ayrımı ölçülmedi.

**DT15.** Bu karşılaştırma iki `const val` dizgisi ve `joinToString` ile ölçüldü; sayısal `const val` birleşimlerinin davranışı bu bölümde ölçülmedi.

## Ölçümlerden Çıkan Alışkanlıklar

`val` ile `var` arasındaki fark, bu dersin ölçümlerinde bir değişkenin bağlanmasıyla nesnenin içeriği arasındaki fark olarak ortaya çıktı. `val` bir kez bağlanan bir ad demektir; bağlanan nesne değiştirilebilir bir liste ise listeye eleman eklenebilir ve `[ada, can]` çıktısı bunu gösterdi. Dolayısıyla bir `val` için "değiştirilemez" demek dikkat ister: yeniden atanamayan bağlanmadır, nesne değildir. İçeriği korumak için salt okunur bir koleksiyon tipi ya da `data class` içinde `val` alanlar kullanılır.

Lambda içinden bir `var` değiştirildiğinde, sayaç dışarıda da göründü: `toplam: 6, cagri: 3`. Ölçüm, lambdanın ve dış kodun aynı değişkene baktığını gösterdi; bunun altında değişkenin bir kutuya sarılması olduğu bilinir, ama bu derste ölçülmedi. Kopya alınan değer ise ayrı kaldı: `kopya: 6, var: 100` satırında `var` yeniden atandığında kopya etkilenmedi. Sık yapılan hata, bir değeri yakalayıp sonra değişkeni değiştirdiğinde yakalanan değerin de değişeceğini sanmaktır; kopya ile referans arasındaki farkı atamanın nerede yapıldığına bakarak ayırmak gerekir.

`const val` ise derleme anı sabitidir ve yalnız temel tip ya da dizgi değeri alabilir; üst düzeyde, bir nesne bildiriminde ya da yardımcı nesnede tanımlanır. Ölçümde iki `const val` birleşimi tek bir nesne olarak ortaya çıktı, çalışma anında hesaplanan birleşim ise içerik olarak eşit ama ayrı bir değer verdi. Pratik kural şudur: bir değer derleme anında bilinebiliyorsa `const val`, bilinemiyorsa `val` yazılır. Java'da aynı ayrım `static final` ile ifade edilir, ama derleme anı sabiti olup olmadığı alanın başlatma ifadesine bağlıdır ve yazımdan okunmaz.

Bu üç gözlemi tek bir cümleye indirgemek gerekirse: bir adın değişip değişmediğini, adın bağlandığı nesnenin değişip değişmediğinden ayrı sorun. Kodu okurken her `val` gördüğünüzde bu iki soruyu birbirinden ayırmak, hataların büyük kısmını önceden yakalar.

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

Tekil ölçüt sabitle sınırlıdır. Aynı metin çalışma anında kurulduğunda ölçüt içeriğe döner: `val-kurulan` ve `var-kurulan` bunun iki örneğidir. Aynı `"kotlin"` metni, bir yerde sabit olarak yazıldığında tekil, başka bir yerde `joinToString` ya da `buildString` ile kurulduğunda içerik ölçütüne düşer. Bu yüzden kodda metin karşılaştırırken `===` yerine `==` kullanılır; ikincisi her iki durumda da doğru yanıtı verir.

## Özet

- `val` yeniden atanamayan, `var` yeniden atanabilir değişkendir; ikisinin de tipi çıkarımla bulunabilir.
- `const val` derleme zamanı sabitidir; değeri derleme sırasında bilinmelidir.
- `val` değişkene ikinci kez atama derleyicide reddedilir.
- `val` ya da `var` seçimi eşitlik ölçütünü belirlemez; değerin sabitten mi çalışma anından mı geldiği belirler.
- Bu dersin ölçütü: **tekil**; sınırlayıcı ölçüm: çalışma anında kurulan aynı metin içerik ölçütüne düşer.

## Sonraki Adım

Bir değişkenin tipi çıkarımla bulunuyordu. Sıradaki derste temel tiplere bakıyoruz: sayılar, karakter ve mantıksal değer. Aynı `1` sayısı bir bağlamda `Int`, başka bir bağlamda `Long` olur; bu iki tipi karıştıran bir `==` neden reddedilir, onu ölçeriz.
