Type-safe builder
- Kotlin kursu
- Uzman
- Ders 5/47
- 5 dk
@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
// @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
@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
____
annotation class MenuDsl
@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 |