带有可选字段的 Kotlin DSL
Kotlin DSL with optional fields
我目前正在学习 Kotlin DSL。
我已经研究它一段时间了,但我无法解决我的用例。我有一个简单的 DSL,我不太关心它的类型,只要我能实现这样的语法即可:
private fun getObj(): SET {
return SET {
ITEM {
A = null
B = "Hello world"
C
// D - exists in DSL but omitted here
}
}
}
在后台,我现在想区分 ITEM
块中设置的某些值。 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)
}
当我有我的最终对象时,我希望能够为 ITEM 下的每个字段说出 4 个不同的阶段:
- 设定值
- 空集
- 未设置值
- 字段省略
我尝试了不同的类型,但没有成功,因为大多数事情都会影响语法。我还尝试更改构建器中的 getter/setters,以便可能在那里捕获更新并有一个额外的内部 属性 得到更新 - 但 get
或 set
都没有被调用对于 null/no 值。还尝试将字段更改为函数,但后来我在 DSL 语法中有丑陋的括号 ()
。
如果有人能帮我解决这个问题就太好了。
提前致谢!
您可以使用接收器来实现这一点。这是一个带有单个参数的示例(在本例中为字段)
//Use like this
val item = ITEM {
A = "Yay"
B //Not omitted, but also not set
//C can be omitted
D = null
}
这相当于
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)
Here's the link to the Kotlin Playground。您可以 运行 它并亲自查看输出。
我目前正在学习 Kotlin DSL。
我已经研究它一段时间了,但我无法解决我的用例。我有一个简单的 DSL,我不太关心它的类型,只要我能实现这样的语法即可:
private fun getObj(): SET {
return SET {
ITEM {
A = null
B = "Hello world"
C
// D - exists in DSL but omitted here
}
}
}
在后台,我现在想区分 ITEM
块中设置的某些值。 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)
}
当我有我的最终对象时,我希望能够为 ITEM 下的每个字段说出 4 个不同的阶段:
- 设定值
- 空集
- 未设置值
- 字段省略
我尝试了不同的类型,但没有成功,因为大多数事情都会影响语法。我还尝试更改构建器中的 getter/setters,以便可能在那里捕获更新并有一个额外的内部 属性 得到更新 - 但 get
或 set
都没有被调用对于 null/no 值。还尝试将字段更改为函数,但后来我在 DSL 语法中有丑陋的括号 ()
。
如果有人能帮我解决这个问题就太好了。
提前致谢!
您可以使用接收器来实现这一点。这是一个带有单个参数的示例(在本例中为字段)
//Use like this
val item = ITEM {
A = "Yay"
B //Not omitted, but also not set
//C can be omitted
D = null
}
这相当于
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)
Here's the link to the Kotlin Playground。您可以 运行 它并亲自查看输出。