【问题标题】:Kotlin DSL with optional fields带有可选字段的 Kotlin DSL
【发布时间】:2020-05-05 18:49:54
【问题描述】:

我目前正在学习 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 很简单,只是价值,但对于 AC 来说就很难了。不知何故,我无法区分 nullno 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/setter,以便在那里捕获更新并有一个额外的内部属性被更新 - 但 getset 都不会调用 null/no 值。还尝试将字段更改为函数,但后来我在 DSL 语法中有难看的括号 ()

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

提前致谢!

【问题讨论】:

    标签: kotlin dsl kotlin-dsl


    【解决方案1】:

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

    //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。您可以运行它并自己查看输出。

    【讨论】:

    • 这看起来不错,正在解决省略的情况。但是它不能解决BC,一个空值和没有值。期望的结果是 ItemValue 类显示include=true,除了省略的情况。仔细想想,我肯定要扩展 ItemValue 类,所需的对象结果看起来像这样:-> isIncludes, Value, isEmpty 然后用例看起来像:A: ItemValue == (true, A, false) B: ItemValue == (true, B, false) C: ItemValue == (true, C, true) @ 987654338@
    • 您更新的代码涵盖了空值的情况,但是它无法区分省略的值和未设置的值,A = null // worksB = "Hello world" // worksC // doesnt work// D - exists in DSL but omitted here // works
    • 是的,解决了。感谢所有的帮助。让我通读一下代码,了解它是如何工作的。
    猜你喜欢
    • 2012-10-07
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    相关资源
    最近更新 更多