【问题标题】:@DSLMarker not limiting the scope of DSL@DSLMarker 不限制 DSL 的范围
【发布时间】:2025-12-17 04:55:01
【问题描述】:

我正在为 HTML 构建一个 Kotlin DSL,以满足我非常具体的要求(因此不使用 kotlinx.html)

        DIV(classes = "div1") {
            +"text1"
            a(href = "#0") {
                +"text2"
                div(classes = "div2") {
                    +"text3"
                    href = "#1"
                }
                div(classes = "div3") {
                    +"text4"
                    href = "#2"
                }
            }
            hr(classes = "hr1")
            span(classes = "span1") {
                +"text5"
            }
        }

在上面的示例中,我可以在a 的任何子元素中调用href,而不必执行this@a.href = ""。我如何限制范围,以便 this 在此示例中仅属于 DIV 类型,并在调用 href 时引发编译器错误,因为 DIV 没有 href 属性?

这是DIV 类的简化版本 https://github.com/persephone-unframework/dsl/blob/master/src/main/kotlin/io/persephone/dsl/element/DIV.kt

@DslMarker
annotation class DivMarker

@DivMarker
class DIV(
    classes: String? = null,
    ....
    init: (DIV.() -> Unit)? = null
) : Tag(
    tagName = "div",
    selfClosing = false
) {

    fun a(
        classes: String? = null,
        ....
        init: (A.() -> Unit)? = null
    ) = A().let {

        this.children.add(it)
        ....
        init?.invoke(it)
        it
    }

    ....

}

同样,A 类也被标记: https://github.com/persephone-unframework/dsl/blob/master/src/main/kotlin/io/persephone/dsl/element/A.kt

@DslMarker
annotation class AMarker

@AMarker
class A(
    href: String? = null,
    ...
    init: (A.() -> Unit)? = null
) : Tag(
    tagName = "a",
    selfClosing = false
) {

    fun div(
        classes: String? = null,
        init: (DIV.() -> Unit)? = null
    ) = DIV().let {

        this.children.add(it)

        ....

        init?.invoke(it)
        it
    }

    ....
}

知道为什么@DslMarker 注释不限制这种情况下的范围以及我该如何解决?

【问题讨论】:

    标签: kotlin dsl


    【解决方案1】:

    似乎注释基类,在本例中为Tag,这是否有效,这可能意味着所有其他注释都没有任何作用?

    @DslMarker
    annotation class TagMarker
    
    @TagMarker
    abstract class Tag(val tagName: String, var selfClosing: Boolean = false): Element {
    
        val children = arrayListOf<Element>()
        val attributes = hashMapOf<String, String>()
    
    

    【讨论】: