CodeBlanks Logo Icon CodeBlanks

Type-safe builder

@DslMarker ile type-safe builder öğrenirsin.

@DslMarker ne işe yarar?

Bir DSL yazarken iç içe lambda bloklarında yanlışlıkla dış bloktaki alıcıyı (receiver) kullanabilirsin. @DslMarker bu sınırlamayı getirir.

@DslMarker annotation class MenuDsl ile bir işaret tanımlarsın. Aynı işareti taşıyan tüm alıcı sınıflar, iç içe bloklarda birbirine karışmaz. Böylece item { name = "Çorba" } içinde yanlışlıkla üst menu bloğuna erişemezsin. Bu, derleme zamanı korumasıdır; runtime yükü yoktur. Kotlin standart kütüphanesinde html { ... } gibi DSL'lerde karşına çıkar.

Bir builder DSL

Bir tip-güvenli builder (type-safe builder) yazmak için bir sınıfa @MenuDsl işareti eklersin ve ona bir extension işlevi verirsin.

Örnek: @MenuDsl class Menu { val items = mutableListOf<Item>(); fun item(block: Item.() -> Unit) { items.add(Item().apply(block)) } }. En dışta fun menu(block: Menu.() -> Unit): Menu = Menu().apply(block) bulunur. Bu sayede menu { item { name = "Çorba" } } yazabilirsin. @DslMarker sayesinde item bloğu içinde yanlışlıkla menu'nun items listesine dokunamazsın.

Uygulama menü DSL yaz

@DslMarker annotation class MenuDsl tanımla. Item sınıfı var name: String = "" ve var price: Int = 0 içersin. @MenuDsl class Menu içinde val items = mutableListOf<Item>() ve fun item(block: Item.() -> Unit) olsun. menu fonksiyonu ve main içinde iki öğe ekle, println(m.items.size) yaz.

Başlangıç kodu

Main.kt
// @DslMarker annotation ve Menu DSL yaz

class Item {
    var name: String = ""
    var price: Int = 0
}

// Menu sınıfını ve menu fonksiyonunu ekle

fun main() {
    val m = menu {
        item { name = "Çorba"; price = 30 }
        item { name = "Pilav"; price = 45 }
    }
    // öğe sayısını yazdır
}

Örnek çözüm

Main.kt
@DslMarker
annotation class MenuDsl
class Item { var name: String = ""; var price: Int = 0 }
@MenuDsl
class Menu {
    val items = mutableListOf<Item>()
    fun item(block: Item.() -> Unit) { items.add(Item().apply(block)) }
}
fun menu(block: Menu.() -> Unit): Menu = Menu().apply(block)
fun main() {
    val m = menu {
        item { name = "Çorba"; price = 30 }
        item { name = "Pilav"; price = 45 }
    }
    println(m.items.size)
}

Beklenen çıktı

2

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 @DslMarker annotation tanımla

Soru
____
annotation class MenuDsl
Cevap
@DslMarker
annotation class MenuDsl

Açıklama: @DslMarker ile DSL işaret sınıfı oluşturulur.

2 @DslMarker neyi engeller?

  • Lambda'nın çalışma zamanı hatasını
  • Inline fonksiyonların derlenmesini
  • Annotation sınıfı tanımlanmasını
  • İç içe DSL bloklarında dış alıcının yanlış kullanımını Doğru cevap

Açıklama: @DslMarker dış bloğun alıcısının iç bloktan yanlışça erişilmesini engeller.

3 Builder parçalarını eşle

Kavram Anlamı
@DslMarker İşaret tanımı
annotation class İşaret sınıfı
@MenuDsl Alıcı işareti
block: Item.() -> Unit Lambda alıcı tipi

Uzman bölümündeki tüm dersler