Kotlin 从DSL块中的语句创建列表

Kotlin 从DSL块中的语句创建列表,kotlin,Kotlin,在尝试构建一个用于验证的DSL时,我正在寻找使用receiver在block/lambda中收集语句的方法。下面是一个没有实际验证逻辑的最小示例: data class Constraint(val hint: String) class Validation(val constraints: List<Constraint>) { companion object { operator fun invoke(init: (ValidationBuilde

在尝试构建一个用于验证的DSL时,我正在寻找使用receiver在block/lambda中收集语句的方法。下面是一个没有实际验证逻辑的最小示例:

data class Constraint(val hint: String)

class Validation(val constraints: List<Constraint>) {

    companion object {
        operator fun invoke(init: (ValidationBuilder.() -> Unit)): Validation {
            return ValidationBuilder().apply(init).build()
        }
    }

    class ValidationBuilder {
        private var constraints: MutableList<Constraint> = mutableListOf()

        operator fun Constraint.unaryPlus() {
            constraints.add(this)
        }

        fun build() = Validation(constraints)
    }
}
我想去掉
unaryPlus
操作符,直接收集块中计算为
约束的单个语句,这样我就可以执行以下操作:

val validation = Validation {
    Constraint("First constraint")
    val secondConstraintHint = "Second constraint"
    Constraint(secondConstraintHint)
}
这有可能吗

为了给大家提供更多的背景,我想要的实际结果将更像这样:

Validation<User> {
    User::firstName {
        val min = 2
        minLength(min) hint "Please provide a first name"
        maxLength(200) // uses default hint
    }
}
验证{
User::firstName{
最小值=2
minLength(min)提示“请提供名字”
maxLength(200)//使用默认提示
}
}

好吧,似乎没有简单的解决方案,因为Kotlin无法处理未赋值、返回或传递的已计算表达式结果

一种可能的解决方法是使用为生成器定义的函数来模拟所需的构造函数:

class ValidationBuilder {
    /* ... */

    fun Constraint(name: String) = 
        full.qualified.name.of.Constraint(name).also(constraints::add)
}
不幸的是,这将要求您复制所有要以这种方式调用的签名


UPD(回复评论):我认为用户定制DSL的惯用方式是为DSL构建者定义自己的扩展:

fun ValidationBuilder.nonEmptyText(min: Int = 1, max: Int = 65.536) = TODO()

如果来自DSL之外的
约束
是一个重要的用例,您可以使用一个特殊的函数(例如
fun ValidationBuilder.Constraint(…)
)来覆盖它,并让用户将其扩展委托给它。

谢谢您的回答。不幸的是,这并不实用,因为用户可以定义附加约束,并且应该在DSL中可用,例如,用户可以定义
fun非空文本(min:Int=1,max:Int=65.536):Constraint
factory方法来创建约束,并且将无法在
ValidationBuilder
@n\l中添加阴影功能,我认为用户端的Kotlin DSL定制通常是通过特定于DSL的扩展来完成的。更新了答案。
fun ValidationBuilder.nonEmptyText(min: Int = 1, max: Int = 65.536) = TODO()