Kotlin - 限制扩展方法范围
Kotlin - Restrict extension method scope
有没有办法限制 DSL 中的扩展方法?
假设我有一个这样的 class 结构:
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 { }
调用令人困惑,因为它在 Outer
中添加了 Middle
,但看起来它正在添加到 Inner
.
有没有办法不允许 middle { }
调用?
您可以使用 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不会在completion中提示错误的函数:
outer {
middle {
inner {
middle { } // error
}
}
}
但是你真的不应该为大型 DSL 这样做。最好按照@KirillRakhman 的建议等待 https://youtrack.jetbrains.com/issue/KT-11551。
编辑: 在我修正了我的示例之后,它变得更小了。对于 class 有一个虚拟函数,毕竟它不是那么多样板文件。
官方限制范围的方式是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
因此最后一个 中间 调用不再可编译。
有没有办法限制 DSL 中的扩展方法?
假设我有一个这样的 class 结构:
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 { }
调用令人困惑,因为它在 Outer
中添加了 Middle
,但看起来它正在添加到 Inner
.
有没有办法不允许 middle { }
调用?
您可以使用 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不会在completion中提示错误的函数:
outer {
middle {
inner {
middle { } // error
}
}
}
但是你真的不应该为大型 DSL 这样做。最好按照@KirillRakhman 的建议等待 https://youtrack.jetbrains.com/issue/KT-11551。
编辑: 在我修正了我的示例之后,它变得更小了。对于 class 有一个虚拟函数,毕竟它不是那么多样板文件。
官方限制范围的方式是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
因此最后一个 中间 调用不再可编译。