@DslMarker: zapobieganie wyciekaniu odbiorcy
Używaj adnotacji @DslMarker do wymuszania reguł zagnieżdżania DSL podczas kompilacji.
@DslMarker: zapobieganie wyciekaniu odbiorcy to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Problem wyciekania odbiorcy
W zagnieżdżonych językach DSL lambda wewnętrznego buildera może przypadkowo uzyskać dostęp do elementów zewnętrznego odbiorcy. Na przykład wewnątrz bloku td { } można wywołać tr { } z zewnętrznego zakresu tabeli — co niemal nigdy nie jest zamierzone.
Jak wygląda wyciekanie odbiorcy
Bez @DslMarker kompilator zezwala na wywoływanie funkcji z zewnętrznego zakresu z dowolnej wewnętrznej lambdy, co prowadzi do niejasnego i podatnego na błędy użycia języka DSL:
// Without @DslMarker — this compiles but is wrong:
html {
body {
table {
tr { // outer scope leaks in
tr { } // calling tr inside tr — nonsensical
}
}
}
}Wprowadzenie @DslMarker
@DslMarker to metaadnotacja stosowana do własnej klasy adnotacji. Każda klasa buildera oznaczona adnotacją DSL będzie miała swój niejawny odbiorca ukryty w zagnieżdżonych lambdach używających tej samej adnotacji DSL.
@DslMarker
annotation class HtmlDsl
@HtmlDsl
class Table
@HtmlDsl
class TrJak działa ukrywanie niejawnego odbiorcy
Gdy dwie zagnieżdżone lambdy mają odbiorców oznaczonych tą samą adnotacją @DslMarker, zewnętrzny odbiorca jest ukrywany wewnątrz lambdy wewnętrznej. Bezpośredni dostęp do niego powoduje błąd kompilacji.
@DslMarker
annotation class HtmlDsl
@HtmlDsl class Html
@HtmlDsl class Body
@HtmlDsl class DivPełny przykład z @DslMarker
Należy zadeklarować adnotację, oznaczyć klasy builderów, a następnie pozwolić, aby zagnieżdżone wywołania metod z zewnętrznego zakresu były wykrywane w czasie kompilacji:
@DslMarker
annotation class MyCfgDsl
@MyCfgDsl
class ServerBuilder {
var port: Int = 8080
fun database(block: DbBuilder.() -> Unit) { /*...*/ }
}
@MyCfgDsl
class DbBuilder {
var url: String = ""
// Cannot call ServerBuilder.port here — compiler error
}Omijanie ograniczenia za pomocą this@
Jeśli rzeczywiście trzeba uzyskać dostęp do zewnętrznego odbiorcy z wewnętrznej lambdy, należy użyć etykietowanego odwołania this@OuterClass. Jest ono jawne i zamierzone, w przeciwieństwie do przypadkowego wyciekania odbiorcy.
fun ServerBuilder.database(block: DbBuilder.() -> Unit) {
val db = DbBuilder()
db.block()
val serverPort = this@ServerBuilder.port // explicit outer access
}@DslMarker z wieloma językami DSL
Różne języki DSL powinny używać różnych adnotacji @DslMarker. Dwa niezależne języki DSL z różnymi znacznikami nie wpływają na siebie nawet wtedy, gdy są zagnieżdżone.
@DslMarker annotation class HtmlDsl
@DslMarker annotation class GradleDsl
// HtmlDsl and GradleDsl receivers do not hide each otherStosowanie do builderów i odbiorców
Adnotację DSL należy zastosować bezpośrednio do klasy buildera. Adnotacja propaguje się do każdego parametru lambdy, którego typem odbiorcy jest ta klasa. Dalsze oznaczanie poszczególnych funkcji nie jest potrzebne.
Obsługa w IDE
IntelliJ IDEA i Android Studio natychmiast oznaczają dostęp do zewnętrznego odbiorcy jako błąd, gdy używana jest adnotacja @DslMarker. Zapewnia to informację zwrotną w czasie rzeczywistym podczas tworzenia lub używania języka DSL.
Projektowanie z myślą o bezpieczeństwie
Dobrze zaprojektowany język DSL łączy każdą klasę buildera z adnotacją @DslMarker. To niewielki narzut związany z adnotacją, który znacznie poprawia wygodę korzystania z DSL i zapobiega całym kategoriom błędów po stronie użytkowników DSL.
Użycie w bibliotece standardowej
Własna adnotacja @DslMarker języka Kotlin jest używana w kotlinx.html, DSL routingu Ktor, skrypcie Gradle Kotlin oraz builderach buildMap/buildList. Jest podstawowym narzędziem każdego zaawansowanego zestawu narzędzi DSL.
Szybkie sprawdzenie
Czemu zapobiega @DslMarker?
Podsumowanie: @DslMarker
Najważniejsze informacje:
- Bez
@DslMarkerzewnętrzni odbiorcy wyciekają do lambd wewnętrznego języka DSL - Należy zdefiniować klasę adnotacji opatrzoną metaadnotacją i zastosować ją do wszystkich klas builderów w języku DSL
- Zagnieżdżone lambdy z tym samym znacznikiem nie mogą przypadkowo wywoływać elementów zewnętrznego zakresu
- Gdy rzeczywiście potrzebny jest dostęp do zewnętrznego zakresu, należy użyć
this@OuterClass
Często zadawane pytania
Czy lekcja „@DslMarker: zapobieganie wyciekaniu odbiorcy” jest bezpłatna?
Tak — pełny tekst „@DslMarker: zapobieganie wyciekaniu odbiorcy” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „@DslMarker: zapobieganie wyciekaniu odbiorcy”?
Używaj adnotacji @DslMarker do wymuszania reguł zagnieżdżania DSL podczas kompilacji. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?
Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „@DslMarker: zapobieganie wyciekaniu odbiorcy”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?
Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Lambda z odbiorcą: podstawa DSL
- @DslMarker: zapobieganie wyciekaniu odbiorcy
- Budowanie bezpiecznego typowo DSL HTML/Config
- Testowanie i rozwijanie DSL bez łamania zgodności użytkowników