Kotlin类型安全生成器DSL,最外层功能的安全性

Kotlin类型安全生成器DSL,最外层功能的安全性,kotlin,dsl,Kotlin,Dsl,我将使用实现DSL的文档中的来创建一些HTML 自Kotlin 1.1以来,@DslMarker注释允许我们限制类中函数的范围,就像示例中的@HtmlTagMarker注释一样。当我们试图编写结构不正确的代码时,会出现如下错误: html { body { body { // this in an error, as it's a function call on the outside Html element } } } 然而,这并不妨碍嵌

我将使用实现DSL的文档中的来创建一些HTML

自Kotlin 1.1以来,
@DslMarker
注释允许我们限制类中函数的范围,就像示例中的
@HtmlTagMarker
注释一样。当我们试图编写结构不正确的代码时,会出现如下错误:

html {
    body { 
        body { // this in an error, as it's a function call on the outside Html element
        }
    }
}
然而,这并不妨碍嵌套最外层的函数,它是DSL的入口点。例如,现在的示例可以毫无问题地记录下来:

html {
    html {
    }
}

在这方面,有没有办法使DSL更安全?

也许这可以用一种更优雅的方式来实现,但我可以建议在具有为接收器类型定义的匹配签名的函数上使用
@Deprecated
注释和
DeprecationLevel.ERROR
,例如:

@Deprecated("Cannot be used in a html block.", level = DeprecationLevel.ERROR)
fun HtmlReceiver.html(action: HtmlReceiver.() -> Unit): Nothing = error("...")
或者这可以是一个成员函数。顺便说一下,IDE完成的行为根据它是扩展还是成员而有所不同

这将使内部调用无效:

html {
    html { // Error: Cannot be used in a html block.
    }
}

顶级函数仍然可以通过其FQN在DSL块内调用,例如
com.example.html{}
,因此此技巧只能防止用户错误调用顶级函数