有没有办法限制DSL中的扩展方法?
假设我有这样的类结构:
class Outer {
fun middle(op: Middle.() -> Unit): Middle {
val middle = Middle()
middle.op()
return middle
}
}
class Middle {
fun inner(op: Inner.() -> Unit): Inner {
val inner = Inner()
inner.op()
return inner
}
}
class Inner
fun outer(op: Outer.() -> Unit): Outer {
val outer = Outer()
outer.op()
return outer
}
然后我可以像这样创建一个调用:
outer {
middle {
inner {
middle { } // Here is the problem
}
}
}
我的问题是,标记为middle { }
的通话令人困惑,因为当Middle
看起来正在添加Outer
时,会向Inner
添加middle { }
。 / p>
有没有办法不允许String[] DoctorEp = new String[107];
void DoctorDec()
{
DoctorEp[0] = "rose";
DoctorEp[1] = "the end of the world";
DoctorEp[2] = "the unquiet dead";
DoctorEp[3] = "aliens of london";
DoctorEp[4] = "world war three";
DoctorEp[5] = "dalek";
DoctorEp[6] = "the long game";
DoctorEp[7] = "father's day";
DoctorEp[8] = "the empty child";
DoctorEp[9] = "the doctor dances";
DoctorEp[10] = "boom town";
}
来电?
答案 0 :(得分:8)
您可以使用deprecated
的解决方法:
class Outer {
fun middle(op: Middle.() -> Unit): Middle {...}
@Deprecated("can not be used inside a Outer block", level = DeprecationLevel.ERROR)
fun outer(op: Outer.() -> Unit): Outer = TODO()
}
class Middle {
fun inner(op: Inner.() -> Unit): Inner {...}
@Deprecated("can not be used inside a Middle block", level = DeprecationLevel.ERROR)
fun middle(op: Middle.() -> Unit): Middle = TODO()
}
class Inner {
@Deprecated("can not be used inside a Inner block", level = DeprecationLevel.ERROR)
fun inner(op: Inner.() -> Unit): Inner = TODO()
}
现在编译器会给你一个错误,IDE在完成时不会建议错误的函数:
outer {
middle {
inner {
middle { } // error
}
}
}
但你真的不应该为大型DSL做这件事。最好像@KirillRakhman建议的那样等待https://youtrack.jetbrains.com/issue/KT-11551。
修改:我修复了我的示例后,它变得更小了。对于一个类有一个虚拟函数,它毕竟不是那么多的样板。
答案 1 :(得分:0)
限制范围的官方方法是DslMarker。
在某些情况下(例如,当您需要注释Java源代码时)它无济于事-在这里使用@Deprecated
。但是请先尝试DslMarker
。
@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class Scope
@Scope
class Outer {
fun middle(op: Middle.() -> Unit): Middle { /**/ }
}
@Scope
class Middle {
fun inner(op: Inner.() -> Unit): Inner {/**/ }
}
class Inner
因此,最后一个 middle 调用不再可编译。