改善DSL语法

时间:2018-10-20 13:48:14

标签: syntax kotlin dsl

要开始学习使用Kotlin语言功能的DSL设计,我有 下面尝试在玩具DSL上创建具有成员的成员组 有名字。我正在寻找以下内容的指针/提示

  1. 如果编译器没有给出分号,如何避免用分号分隔组
  

Groups.kt:31:45:错误:未解决的引用:成员     val grp =组{成员{名称(“鲍勃”)}成员{名称(“桑迪”)}}

  1. 我可以使用lambda来设置name而不是函数调用吗?

  2. 我可以避免在类name中使MEMBER变得可变吗?

我的代码是

fun group(create: GROUP.() -> Unit) = GROUP().apply(create)

class GROUP {
    private val members = mutableSetOf<MEMBER>()

    fun member(create: MEMBER.() -> Unit) {
        val member = MEMBER()
        member.create()
        members.add(member)
    }

    override fun toString() = members.toString()

}

class MEMBER() {
    var name = ""
    set(value) {
        field = value
    }

    fun name(nameToSet: String) {
        name = nameToSet
    }
    override fun toString() = "MEMBER(" + name + ")"
}

fun main(args: Array<String>) {
    val grp = group { member { name ("Bob") }; member { name ("Sandy") } }
    println(grp)
}

当前上述代码的输出为

  

[鲍勃(成员),桑迪(成员)]

1 个答案:

答案 0 :(得分:1)

  

如何避免用分号分隔组

使用惯用格式,使用单独的行。毕竟,DSL的全部目的是通过显示层次结构来使代码非常易读,而在一行上完成所有操作都将达到令人讨厌的目的:

val grp = group { 
    member { 
        name ("Bob") 
    }
    member { 
        name ("Sandy") 
    } 
}
  

我可以使用lambda来设置名称而不是函数调用吗?

删除名称函数并简单地为属性分配一个值会更合乎逻辑和习惯:

name = "Bob"

但是,您也可以用

替换您的姓名功能
fun name(block: () -> String) {
    this.name = block()
}

并使用

name {
    "Sandy"
}
  

我可以避免在MEMBER类中使名称可变吗?

是的:传递给member()函数的lambda将自定义一个额外的MemberBuilder类,该类是可变的,但允许创建一个不变的MEMBER:

fun group(create: GROUP.() -> Unit) = GROUP().apply(create)

class GROUP {
    private val members = mutableSetOf<MEMBER>()

    fun member(configure: MemberBuilder.() -> Unit) {
        val memberBuilder = MemberBuilder()
        memberBuilder.configure()
        members.add(memberBuilder.build())
    }

    override fun toString() = members.toString()

}

class MEMBER(val name: String) {
    override fun toString() = "MEMBER($name)"
}

class MemberBuilder {
    var name = "";

    fun build() = MEMBER(name)
}

fun main(args: Array<String>) {
    val grp = group {
        member {
            name = "Bob"
        }
        member {
            name = "Sandy"
        }
    }
    println(grp)
}

此外,请注意,按照惯例,类是PascalCased,而不是ALL_CAPS。