---
title: Fonksiyonlar
source: 'https://academia.sh/tr/kurslar/kotlin/fonksiyonlar'
course: 'Kotlin Dili'
language: tr
updated: '2026-10-21T05:02:39+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - '`fun` ile fonksiyon bildirmek; varsayılan değerli parametre, adlandırılmış argüman ve `vararg` kullanmak'
    - 'Varsayılan değerin her çağrıda yeniden hesaplandığını ve bunun eşitlik ölçütüne etkisini açıklamak'
    - 'Fonksiyon referansı almanın ayrı ama eşit nesneler verdiğini ölçmek'
---

# Fonksiyonlar

Varsayılan değerli parametreleri, adlandırılmış argümanları ve `vararg` parametresini tanıtır; fonksiyon referansının her alınışta ayrı ama eşit bir nesne verdiğini ölçer.

Denetim akışında bir değeri dallara dağıtmayı ve bir aralığı dolaşmayı gördük. Bu derste o akışı adlandırılmış, yeniden kullanılabilir parçalara paketliyoruz: fonksiyonlar. Önce bir fonksiyonun parametrelerini nasıl esnetebileceğimize bakıyoruz, sonra aynı soruyu fonksiyonların kendisine soruyoruz: aynı fonksiyonu iki kez bir değer olarak aldığımızda iki eşit nesne mi elde ederiz, yoksa tek nesne mi?

## Parametreleri Esnetmek

Kotlin'de fonksiyon `fun` anahtar sözcüğüyle bildirilir: ad, parantez içinde `ad: Tip` biçiminde parametreler, ardından iki nokta ve dönüş tipi gelir. Gövde tek bir ifadeyse `=` ile yazılabilir. Üç özellik parametre listesini esnetir.

Birincisi varsayılan değerdir: bir parametreye `= değer` eklenirse çağıran onu atlayabilir. İkincisi adlandırılmış argümandır (named argument): çağrıda `punctuation = "?"` yazılırsa değer sıraya göre değil adına göre bağlanır ve aradaki parametreler varsayılanlarında kalır. Üçüncüsü `vararg` parametresidir: bir parametre `vararg` ile işaretlenirse çağıran istediği kadar değer verebilir, fonksiyon içinde bunlar bir dizi olarak görünür. Elindeki bir diziyi `vararg` parametresine vermek için dizinin önüne `*` konur.

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

Varsayılan değer bir sabit olmak zorunda değildir; herhangi bir ifade olabilir. Çağıran parametreyi atladığında o ifade çağrı anında hesaplanır, bu yüzden aynı fonksiyonun iki çağrısı varsayılandan iki ayrı sonuç alabilir. Adlandırılmış argüman da yalnız sıra kolaylığı değildir: çağrıyı okuyan biri `punctuation = "?"` yazımından değerin neye ait olduğunu fonksiyonun bildirimine bakmadan anlar. İkinci bölümde varsayılan değerin bu davranışını ölçeceğiz.

Aşağıdaki program üç özelliği birlikte kullanır. `greet` iki varsayılan değerli parametre taşır, `sum` ise `vararg` alır.

```kotlin
// Main.kt — varsayilan deger, adlandirilmis arguman ve vararg
fun greet(name: String, greeting: String = "Merhaba", punctuation: String = "."): String =
    "$greeting, $name$punctuation"

fun sum(vararg numbers: Int): Int = numbers.sum()

fun main() {
    println(greet("Ada"))
    println(greet("Ada", punctuation = "?"))
    println(greet(greeting = "Selam", name = "Can"))
    println(sum())
    println(sum(1, 2, 3))
    val values = intArrayOf(4, 5)
    println(sum(*values, 6))
}
```

```
Merhaba, Ada.
Merhaba, Ada?
Selam, Can.
0
6
15
```

İlk iki satır adı tek başına verilen ve noktalamayı adlandırılmış argümanla değiştirilen çağrıları gösterir: `greeting` ve `punctuation` atlandığında `Merhaba` ile nokta kullanıldı, `punctuation = "?"` yazıldığında yalnız noktalama değişti. Üçüncü satırda argümanlar sıra dışı, adlarıyla verildi ve `Selam, Can.` çıktı. Son üç satır `vararg` içindir: hiç değer verilmediğinde toplam `0`, üç değerde `6` oldu; `sum(*values, 6)` ise dizinin iki öğesini ve ek altıyı birlikte topladı ve `15` verdi.

**DT38.** Varsayılan değerler ve `vararg` yalnız `String` ve `Int` parametreleriyle ölçüldü; türü bir sınıf olan parametreler için aynı davranış bu derste ayrıca sınanmadı.

**DT39.** Adlandırılmış argümanla sıra değiştirme yalnız bir çağrıda gösterildi; adlandırılmış ve konumsal argümanların aynı çağrıda karıştırılmasının kuralları bu dersin dışındadır.

## Fonksiyon Referansı ve Varsayılan Değer

Dersin ölçümü iki şeye bakar. Birincisi fonksiyon referansıdır (function reference): `::plain` yazımı, `plain` fonksiyonunu çağırmadan bir değer olarak verir. Aynı yazımı iki kez kullanmak aynı nesneyi mi verir, ayrı nesneleri mi? İkincisi varsayılan değerdir: `into: MutableList<Int> = mutableListOf()` varsayılanı her çağrıda yeni bir liste mi kurar, yoksa tek bir listeyi mi paylaşır?

`collectMutable` bir öğeyi aldığı listeye ekler ve listeyi döndürür; liste verilmezse varsayılan olan boş değiştirilebilir liste kullanılır. `defaultList` ise `listOf()` varsayılanını doğrudan döndürür. Üç gözlem yazıyoruz: `fonksiyon-referansi`, iki `::plain` ve farklı olarak `::other`; `varsayilan-mutableListOf`, `collectMutable(1)` iki kez ve `collectMutable(2)` farklı değer; `varsayilan-listOf`, `defaultList()` iki kez ve `listOf(1)` farklı değer.

```kotlin
// Main.kt — fonksiyon referansi ve varsayilan degerler
fun plain(n: Int): Int = n

fun other(n: Int): Int = n + 1

fun collectMutable(item: Int, into: MutableList<Int> = mutableListOf()): MutableList<Int> {
    into.add(item)
    return into
}

fun defaultList(into: List<Int> = listOf()): List<Int> = into

fun main() {
    val checks = listOf(
        Criterion("fonksiyon-referansi", ::plain, ::plain, ::other),
        Criterion("varsayilan-mutableListOf", collectMutable(1), collectMutable(1), collectMutable(2)),
        Criterion("varsayilan-listOf", defaultList(), defaultList(), listOf(1)),
    )
    for (check in checks) {
        check.report()
    }
    summarize(checks)
}
```

```
fonksiyon-referansi: ayni-nesne=false, ikiz=true, farkli=false -> icerik
varsayilan-mutableListOf: ayni-nesne=false, ikiz=true, farkli=false -> icerik
varsayilan-listOf: ayni-nesne=true, ikiz=true, farkli=false -> tekil
tekil: 1
kimlik: 0
icerik: 2
kismi-icerik: 0
```

`fonksiyon-referansi` satırında `ayni-nesne=false` ve `ikiz=true` görünür: iki `::plain` yazımı ayrı nesne verdi, ama bu iki nesne `==` ile eşit çıktı. Ayrı nesne, eşit içerik: içerik ölçütü. `varsayilan-mutableListOf` da içeriktir. İki çağrı iki ayrı liste kurdu, ikisi de `[1]` taşıdığı için eşit. Varsayılan değer fonksiyon her çağrıldığında yeniden hesaplanır; bir çağrıda eklenen öğe sonraki çağrıya sızmaz.

`varsayilan-listOf` ise tekildir: `ayni-nesne=true`. Boş `listOf()` çağrısı iki seferde aynı nesneyi verdi. Özet satırları bir tekil, sıfır kimlik, iki içerik ve sıfır kısmi içerik gösterir.

**DT40.** Fonksiyon referansı eşitliği yalnız üst düzey fonksiyonlarla ölçüldü; bir nesneye bağlı referansın (`nesne::ad`) nasıl eşitlendiği bu derste ölçülmedi.

**DT41.** Boş `listOf()` çağrısının tek nesne vermesi Kotlin 2.4.21'in JVM hedefinde ölçüldü; bu davranış listenin gerçekleştirimine bağlı olduğundan başka sürümler için aynısı iddia edilmiyor.

## Varsayılan Değer Her Çağrıda Hesaplanır

Varsayılan değerin bir ifade olabildiğini gördük. Asıl soru ifadenin ne zaman çalıştığıdır: fonksiyon tanımlanırken bir kez mi, yoksa her çağrıda mı? Aşağıdaki blok varsayılan değeri bir sayaç artıran fonksiyondan alır ve bir parametrenin varsayılanının öncekine bağlı olabildiğini de dener.

```kotlin
// Main.kt — varsayilan deger her cagrida hesaplanir
var counter = 0

fun nextId(): Int {
    counter++
    return counter
}

fun label(text: String, id: Int = nextId(), width: Int = text.length): String =
    "$text#$id/$width"

fun main() {
    println(label("ab"))
    println(label("abc"))
    println(label("abc", id = 100))
    println(label("abc", width = 1))
    println(counter)
}
```

```
ab#1/2
abc#2/3
abc#100/3
abc#3/1
3
```

İlk çağrı `ab#1/2` verdi: `id` için `nextId()` çalıştı ve 1 üretti, `width` varsayılanı `text.length` olduğu için 2 oldu. İkinci çağrı `abc#2/3` verdi; sayaç ikinci kez arttı. Demek ki varsayılan değer her çağrıda yeniden hesaplanır. Üçüncü çağrıda `id` açıkça 100 verildi ve `abc#100/3` basıldı; bu durumda `nextId()` hiç çalışmadı. Dördüncü çağrı `abc#3/1` verdi: `width` adlandırılmış argümanla 1 oldu, `id` için sayaç yeniden çalıştı ve 3 üretti. Son satır `counter` değerini `3` olarak verdi: dört çağrıdan yalnız üçü varsayılan `id` kullandı.

Bu iki şeyi kanıtlar. Birincisi, varsayılan ifade çağrı anında çalışır; yan etkisi varsa her çağrıda tekrar eder. İkincisi, varsayılanlar kendinden önceki parametrelere erişebilir (`width`, `text`'e bakar). Sık yapılan hata, varsayılan değerin tanım anında dondurulduğunu sanmaktır; Python'da değiştirilebilir varsayılan değerin tanımda bir kez hesaplanması bilinen bir tuzaktır, Kotlin'de böyle bir tuzak yoktur. Java'da varsayılan parametre yoktur; aynı etki aşırı yükleme ile elde edilir.

**DT42.** Varsayılan değer ölçümü üst düzey bir sayaçla yapıldı; çok iş parçacıklı bir ortamda sayaç davranışı bu derste ölçülmedi.

## Unit, Nothing ve Yerel Fonksiyon

Dönüş değeri yazılmayan bir fonksiyon aslında bir şey döndürür. Aşağıdaki blok `Unit` dönen bir fonksiyonu yazdırır, `Nothing` dönen bir fonksiyonu `try` içinde yakalar ve başka fonksiyonun içine yerleştirilmiş bir fonksiyon kullanır.

```kotlin
// Main.kt — Unit, Nothing ve yerel fonksiyon
fun nothingToReturn() {
}

fun fail(message: String): Nothing = throw IllegalStateException(message)

fun total(values: List<Int>): Int {
    fun square(n: Int) = n * n
    var sum = 0
    for (v in values) {
        sum += square(v)
    }
    return sum
}

fun main() {
    println(nothingToReturn())
    println(nothingToReturn() === Unit)
    println(total(listOf(1, 2, 3)))
    val result = try {
        fail("durdu")
    } catch (e: IllegalStateException) {
        e.message
    }
    println(result)
}
```

```
kotlin.Unit
true
14
durdu
```

İlk satır `kotlin.Unit` verdi: bir şey döndürmediğini sandığımız fonksiyon aslında `Unit` adlı tekil nesneyi döndürür ve `println` bunu yazdırabilir. İkinci satırdaki `true`, `nothingToReturn() === Unit` karşılaştırmasının doğru olduğunu gösterir: `Unit` tek bir nesnedir. Bu, Java'daki `void` ile temel bir farktır; `void` bir değer değildir, `Unit` ise gerçek bir değerdir ve bu yüzden genel tiplerde `Unit` kullanılabilir.

Üçüncü satır `14`, yani 1, 4 ve 9'un toplamıdır. `square` fonksiyonu `total` içinde tanımlıdır ve yalnız oradan çağrılabilir. Yerel fonksiyon dış fonksiyonun değişkenlerine erişebilir; burada kullanılmadı ve erişim ölçülmedi.

Son satır `durdu` verdi. `fail` fonksiyonunun dönüş tipi `Nothing`: hiçbir zaman normal biçimde dönmez, hep istisna fırlatır. Derleyici bunu bilir; `fail(...)` çağrısı `try` içinde değer üretmek zorunda olduğu için yakalanan istisnanın iletisi sonuç oldu. Sık yapılan hata `Nothing` tipini `Unit` ile karıştırmaktır. `Unit` döner ve devam eder, `Nothing` ise hiç dönmez.

**DT43.** `Nothing` ölçümü bir istisna fırlatan fonksiyonla yapıldı; sonsuz döngü ya da `exitProcess` çağıran fonksiyonların `Nothing` ile işaretlenmesi bu derste ölçülmedi.

## Aşırı Yükleme Seçimi ve Uzantı Fonksiyonu

Aynı adı taşıyan fonksiyonlar parametre tipine göre seçilir. Aşağıdaki blok dört `show` fonksiyonu tanımlar ve beş farklı çağrıyla hangisinin seçildiğine bakar. Sonra bir `Int` ve bir `String` üzerine uzantı fonksiyonu yazar ve bir `MutableList` parametresinin çağıran tarafı nasıl etkilediğini gösterir.

```kotlin
// Main.kt — asiri yukleme secimi, uzanti fonksiyonu ve parametre
fun show(x: Int) = "Int"
fun show(x: Long) = "Long"
fun show(x: Any) = "Any"
fun show(x: String) = "String"

fun Int.isEven(): Boolean = this % 2 == 0

fun String.initials(): String = split(" ").joinToString("") { it.take(1).uppercase() }

fun modify(list: MutableList<Int>) {
    list.add(99)
}

fun main() {
    println(show(1))
    println(show(1L))
    println(show("a"))
    val any: Any = "a"
    println(show(any))
    println(show(1.5))
    println(4.isEven())
    println("ada lovelace".initials())
    val nums = mutableListOf(1)
    modify(nums)
    println(nums)
}
```

```
Int
Long
String
Any
Any
true
AL
[1, 99]
```

`show(1)` `Int`, `show(1L)` `Long`, `show("a")` `String` verdi: derleyici en özel eşleşmeyi seçer. Dördüncü satır ilginçtir. `any` değişkeni çalışma anında bir `String` taşır, ama tipi `Any` olarak bildirildiği için `show(any)` `Any` sürümünü seçti. Aşırı yükleme çözümü derleme anında, değişkenin bildirilen tipine göre yapılır; çalışma anı tipi seçimi etkilemez. Java'da da aşırı yükleme derleme anında çözülür; sanal yöntem çağrısı ise çalışma anı tipine göre çözülür ve ikisi karıştırılmamalıdır. `show(1.5)` yalnız `Any` sürümüne uyduğu için `Any` verdi.

`4.isEven()` `true` verdi ve `"ada lovelace".initials()` `AL` verdi: uzantı fonksiyonu mevcut bir tipe, tipin kendisini değiştirmeden yeni bir çağrı biçimi ekler. Uzantı fonksiyonu statik olarak çözülür; bir sınıfın gerçek bir üyesi değildir.

Son satır `[1, 99]` verdi. `modify` fonksiyonu parametre olarak aldığı listeye ekleme yaptı ve çağıran taraf bunu gördü. Kotlin'de referansın kendisi değer olarak kopyalanır: nesne paylaşılır, ama fonksiyon çağıranın değişkenini başka bir nesneye bağlayamaz; parametre değişkeni de zaten yeniden atanamaz. Sık yapılan hata, fonksiyona geçen koleksiyonun içinde değişiklik yapıp bunun yerel kalacağını sanmaktır.

**DT44.** Aşırı yükleme seçimi dört tanımla ve beş çağrıyla ölçüldü; `Int` ve `Long` yanında `Short` ya da `Byte` argümanlarının hangi sürüme gittiği bu derste ölçülmedi.

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

Fonksiyon tanımında ölçümlerin gösterdiği ilk şey, varsayılan değerin bir ifade olduğu ve her çağrıda yeniden çalıştığıdır. Bu, Python'daki değiştirilebilir varsayılan tuzağını Kotlin'de ortadan kaldırır, ama başka bir riski doğurur: varsayılan ifadenin yan etkisi varsa, çağrı sayısı program davranışını etkiler. Ölçümde `counter` değeri dört çağrıdan sonra üç oldu, çünkü yalnız üç çağrıda varsayılan değer kullanıldı. Varsayılan ifadeleri yan etkisiz tutmak, bu yüzden iyi bir alışkanlıktır; sayaç artırmak gibi işler açık bir çağrı olarak gövdede yapılmalıdır.

`Unit` ve `Nothing` ayrımı tip sisteminin kullanışlı bir parçasıdır. `Unit` döndüren fonksiyonun tekil bir değer döndürdüğünü ölçtük; bu yüzden `Unit` genel tiplerde sorunsuz kullanılır. `Nothing` ise hiç dönmeyen ifadenin tipidir ve bu sayede `val x = y ?: fail("yok")` gibi bir yazım `x`'in boş olmayan tipte kalmasını sağlar. Derleyici `fail` fonksiyonundan sonra kodun çalışmayacağını bilir, bu yüzden erişilemeyen kod uyarısı verebilir.

Aşırı yüklemede seçim derleme anında yapılır ve bildirilen tipe bakar. `any` değişkeni bir `String` taşıdığı hâlde `Any` sürümü seçildi. Bu davranış, sanal yöntem çağrısının çalışma anı tipine göre çözülmesinden farklıdır ve ikisini karıştıran kod beklenmedik bir sürümü çağırır. Bir aşırı yükleme kümesi büyüdükçe hangi çağrının hangi sürüme gittiğini izlemek güçleşir; bu durumda adlandırılmış fonksiyonlar (`showInt`, `showLong`) daha okunur olabilir.

Uzantı fonksiyonları tipi değiştirmeden çağrı biçimi ekler. Bir kütüphane sınıfına yöntem eklemek istediğinizde, alt sınıf oluşturmak yerine uzantı yazmak çoğu zaman yeterlidir. Ama uzantı gerçek bir üye değildir; sınıfın özel alanlarına erişemez ve statik olarak çözülür, yani çalışma anındaki tipe göre seçilmez.

Parametre olarak geçen değiştirilebilir koleksiyon, çağıran tarafta da değişir. Bunu istemiyorsanız fonksiyon parametresini salt okunur `List` tipinde alın ya da kopyasını çıkarın. Ölçümdeki `[1, 99]` çıktısı bu tuzağın kısa bir kanıtıdır.

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

İçerik ölçütü fonksiyon referansı için geçerlidir ama referansın her alınışta ayrı bir nesne olduğunu bir sözleşme gibi okumamak gerekir: ölçülen şey, iki alınışın `==` ile eşit çıkmasıdır. Aynı derste `listOf()` varsayılanı tekil çıktı. Yani varsayılan değer yazımı tek başına ölçütü belirlemez: `mutableListOf()` her çağrıda yeni bir nesne kurduğu için içerik, `listOf()` aynı boş listeyi döndürdüğü için tekildir. Bir parametrenin varsayılanına bakarken ölçüt, o ifadenin ne kurduğuna bağlıdır.

## Özet

- `fun` ile bildirilen fonksiyonda varsayılan değerli parametre, adlandırılmış argüman ve `vararg` çağrıyı esnetir; `*` bir diziyi `vararg` parametresine açar.
- Varsayılan değer her çağrıda yeniden hesaplanır; `mutableListOf()` varsayılanı çağrılar arasında paylaşılmaz.
- `::plain` gibi iki fonksiyon referansı ayrı nesnelerdir ama `==` ile eşittir: içerik.
- Boş `listOf()` varsayılanı iki çağrıda aynı nesneyi verdi: tekil.
- Bu dersin ölçütü: **içerik**; sınırlayıcı ölçüm: `listOf()` varsayılanı tekildir, `mutableListOf()` varsayılanı içeriktir.

## Sonraki Adım

Fonksiyonları bir değer olarak alıp vermeyi gördük. Bir sonraki derste fonksiyonu yerinde yazmaya geçiyoruz: lambdalar ve yüksek mertebeden fonksiyonlar. Orada aynı soruyu iki lambda için soruyoruz; iki lambda aynı nesne mi, eşit mi, yoksa ikisi de değil mi.
