带有可选字段的Kotlin DSL

带有可选字段的Kotlin DSL,kotlin,dsl,kotlin-dsl,Kotlin,Dsl,Kotlin Dsl,我目前正在学习Kotlin DSL 我已经玩了一段时间,但我无法解决我的用例。我有一个简单的DSL,我不在乎它有多少类型,只要我能实现如下语法: private fun getObj(): SET { return SET { ITEM { A = null B = "Hello world" C // D - exist

我目前正在学习Kotlin DSL

我已经玩了一段时间,但我无法解决我的用例。我有一个简单的DSL,我不在乎它有多少类型,只要我能实现如下语法:

    private fun getObj(): SET {
        return SET {
            ITEM {
                A = null
                B = "Hello world"
                C
                // D - exists in DSL but omitted here
            }
        }
    }
在后台,我现在想区分
块中设置的某些值
B
很容易,它只是一个值,但对于
A
C
来说就很难了。不知何故,我无法区分
null
no value
集合。目前我的生成器看起来是这样的,但我愿意更改它以实现上述语法:

class ITEMBuilder {
    var A: String? = null
    var B: String? = null
    var C: String? = null
    var D: String? = null

    fun build() = ITEM(
        ItemValue(A),
        ItemValue(B),
        ItemValue(C),
        ItemValue(D)
    )
}

class ItemValue(val include: Boolean? = false, val value: String? = null) {
    constructor(value: String? = null): this(null != value, value)
}
当我有了我的最终目标时,我希望能够告诉项目下每个字段的4个不同阶段:

  • 值集
  • 空集
  • 无值集
  • 省略字段
我尝试了不同的类型,但没有成功,因为大多数事情都会影响语法。我还尝试更改构建器中的getter/setter,以便在那里捕获更新,并有一个额外的内部属性进行更新-但是无论是
get
还是
set
都不会调用null/no值。还试图将字段更改为函数,但DSL语法中出现了难看的括号
()

如果有人能帮我解决这个问题就太好了


提前谢谢

您可以使用接收器来实现这一点。下面是一个带有单个参数的示例(本例中为字段)

//像这样使用
val项目=项目{
A=“耶”
B//未省略,但也未设置
//C可以省略
D=零
}
这相当于

Item(//Included and set to "Yay"
     a=ItemValue(include=true, hasBeenSet=true, value="Yay"), 
     //Included, but not yet set
     b=ItemValue(include=true, hasBeenSet=false, value=null), 
     //Not included, and so not yet set
     c=ItemValue(include=false, hasBeenSet=false, value=null), 
     //Included, and set to null (Same as A)
     d=ItemValue(include=true, hasBeenSet=true, value=null))
您可以在
String?
类型的额外字段的帮助下执行此操作,并重写其设置程序以修改
ItemValue
类型的实际字段。我在
ItemValue
中包含了一个
hasBeenSet
属性,以显示它是否已设置

要将属性标记为包含而不进行设置,可以重写getter,使其修改实际字段,使其成为
ItemValue(true,false)
,这意味着它们已包含但未设置

class Builder {
    var A: String? = null
        set(value) {
            a = ItemValue(true, true, value)
        }
        get() {
            a = ItemValue(true, false)
            return field
        }
    var B: String? = null
        set(value) {
            b = ItemValue(true, true, value)
        }
        get() {
            b = ItemValue(true, false)
            return field
        }
    var C: String? = null
        set(value) {
            c = ItemValue(true, true, value)
        }
        get() {
            c = ItemValue(true, false)
            return field
        }
    var D: String? = null
        set(value) {
            d = ItemValue(true, true, value)
        }
        get() {
            d = ItemValue(true, false)
            return field
        }

    var a: ItemValue = ItemValue(false, false)
    var b: ItemValue = ItemValue(false, false)
    var c: ItemValue = ItemValue(false, false)
    var d: ItemValue = ItemValue(false, false)

    fun build(): Item {
        return Item(a, b, c, d)
    }
}

fun ITEM(setters: Builder.() -> Unit): Item {
    val builder = Builder()
    builder.setters()
    return builder.build()
}

data class Item(val a: ItemValue, val b: ItemValue, val c: ItemValue, val d: ItemValue)
data class ItemValue(val include: Boolean, val hasBeenSet: Boolean, val value: String? = null)

。您可以自己运行它并查看输出。

这看起来不错,解决了省略的情况。但是,它不能解决
B
C
的空值和无值问题。期望的结果是ItemValue类显示除省略的情况外的所有情况的
include=true
。仔细想想,我肯定必须扩展
ItemValue
类,期望的对象结果如下:
->isIncludes,Value,isEmpty
,然后用例将如下所示:
A:ItemValue==(true,A,false)
B:ItemValue==(true,B,false)
C:ItemValue==(true,C,true)
D:ItemValue==(false,D,true)
您更新的代码涵盖了空值的情况,但是它无法区分省略的值和未设置的值,
A=null//工作
B=“Hello world”//works
C//不工作
//D-存在于DSL中,但在这里省略了//works
是的,解决了它。谢谢你的帮助。让我通读代码,了解它是如何工作的。