改进 DSL 语法
Improving DSL syntax
要开始使用 Kotlin 语言功能学习 DSL 设计,我有
下面尝试使用玩具 DSL 来创建具有成员的成员组
有名字。我正在寻找pointers/hints以下
- 如果编译器没有给出分号,我如何避免必须用分号分隔组
Groups.kt:31:45: error: unresolved reference: member
val grp = group { member { name ("Bob") } member { name ("Sandy") } }
我可以使用 lambda 来设置 name
而不是函数调用吗?
我可以避免 name
在 class 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)
}
目前上面代码的输出是
[MEMBER(Bob), MEMBER(Sandy)]
How can I avoid having to separate groups by a semicolon
通过使用惯用格式,使用单独的行。毕竟,DSL 的全部意义在于通过显示层次结构使代码更具可读性,而在一行上完成所有事情会破坏整个目的:
val grp = group {
member {
name ("Bob")
}
member {
name ("Sandy")
}
}
Can I get to use a lambda for setting name instead of function call?
删除 name 函数并简单地为 属性:
赋值会更合乎逻辑和惯用
name = "Bob"
但是是的,你也可以用
替换你的名字函数
fun name(block: () -> String) {
this.name = block()
}
并使用
name {
"Sandy"
}
Can I avoid having to have name be mutable in class MEMBER?
是:传递给 member() 函数的 lambda 将自定义一个额外的 MemberBuilder class,它是可变的,但允许创建一个不可变的 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)
}
此外,请注意,按照惯例,classes 是 PascalCased,而不是 ALL_CAPS。
要开始使用 Kotlin 语言功能学习 DSL 设计,我有 下面尝试使用玩具 DSL 来创建具有成员的成员组 有名字。我正在寻找pointers/hints以下
- 如果编译器没有给出分号,我如何避免必须用分号分隔组
Groups.kt:31:45: error: unresolved reference: member val grp = group { member { name ("Bob") } member { name ("Sandy") } }
我可以使用 lambda 来设置
name
而不是函数调用吗?我可以避免
name
在 classMEMBER
中可变吗?
我的密码是
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)
}
目前上面代码的输出是
[MEMBER(Bob), MEMBER(Sandy)]
How can I avoid having to separate groups by a semicolon
通过使用惯用格式,使用单独的行。毕竟,DSL 的全部意义在于通过显示层次结构使代码更具可读性,而在一行上完成所有事情会破坏整个目的:
val grp = group {
member {
name ("Bob")
}
member {
name ("Sandy")
}
}
Can I get to use a lambda for setting name instead of function call?
删除 name 函数并简单地为 属性:
赋值会更合乎逻辑和惯用name = "Bob"
但是是的,你也可以用
替换你的名字函数fun name(block: () -> String) {
this.name = block()
}
并使用
name {
"Sandy"
}
Can I avoid having to have name be mutable in class MEMBER?
是:传递给 member() 函数的 lambda 将自定义一个额外的 MemberBuilder class,它是可变的,但允许创建一个不可变的 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)
}
此外,请注意,按照惯例,classes 是 PascalCased,而不是 ALL_CAPS。