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

时间:2017-04-18 09:19:38

标签: kotlin dsl

我将使用实现DSL的文档中的official example来创建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更安全?

1 个答案:

答案 0 :(得分:10)

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

@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.
    }
}

(demo of this code)

顶层函数仍然可以通过其FQN在DSL块内调用,例如com.example.html { },所以这个技巧只能保护用户不要错误地调用顶级函数。