Kotlin型安全构建器DSL,最外层功能的安全性

zsm*_*b13 8 dsl kotlin

我将使用实现DSL创建的文档中的官方示例.

从Kotlin 1.1开始,@DslMarker注释允许我们限制类中函数的范围,就像@HtmlTagMarker注释中的示例一样.当尝试编写错误的结构化代码时,这会给我们一个错误:

html {
    body { 
        body { // this in an error, as it's a function call on the outside Html element
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这并不能阻止嵌套最外层函数,这是DSL的入口点.例如,使用现在的示例,可以毫无问题地写下来:

html {
    html {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

hot*_*key 10

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

@Deprecated("Cannot be used in a html block.", level = DeprecationLevel.ERROR)
fun HtmlReceiver.html(action: HtmlReceiver.() -> Unit): Nothing = error("...")
Run Code Online (Sandbox Code Playgroud)

或者这可以是成员函数.顺便说一句,IDE完成的行为有点不同,具体取决于它是扩展还是成员.

这将使内部调用无效:

html {
    html { // Error: Cannot be used in a html block.
    }
}
Run Code Online (Sandbox Code Playgroud)

(此代码的演示)

顶层函数仍然可以通过其FQN在DSL块内调用,例如com.example.html { },因此该技巧仅保护用户不会错误地调用顶级函数.