【问题标题】:DSL, extending an interface method with a lambda with receiver as argumentDSL,使用接收器作为参数的 lambda 扩展接口方法
【发布时间】:2021-10-01 09:23:06
【问题描述】:

我有以下接口,其中一个函数接受与接口本身相同类型的接收器的 lambda:

interface WebhookEventInterface<T> {

    operator fun invoke(block: WebhookEventInterface<T>.() -> Unit) {..}
}

现在我想用另一个接口扩展这个接口,在前一个接口的基础上提供额外的功能/特性,比如:

interface PushPullRequestFeatures<T> : WebhookEventInterface<T> {

    override operator fun invoke(block: PushPullRequestFeatures<T>.() -> Unit) {..}
}

编译器当然会抱怨,因为 PushPullRequestFeatures 与他的超级 invoke 方法存在函数签名冲突,而 override 不会覆盖任何内容。

如何在提供相同类型的接收器的同时覆盖PushPullRequestFeatures 中的超级WebhookEventInterfaceinvoke 方法?

【问题讨论】:

  • 如果你想不可能PushPullRequestFeatures.invoke调用WebhookEventInterface&lt;T&gt;.() -&gt; Unit,那么这与“继承WebhookEventInterface”的含义相矛盾。如果您只想为PushPullRequestFeatures 的实现者提供额外的重载,请不要使用override
  • @Sweeper 我想简单地覆盖它以提供带有新接收器的 lambda。如果我在PushPullRequestFeatures 中省略了override,那么仍然存在声明冲突
  • 你的目标是 JVM 吗?只需添加 @JvmName 注释即可为其中一个重载提供不同的 JVM 名称。
  • @Sweeper 是的,我试过了,但在这种情况下似乎不可能'@JvmName' annotation is not applicable to this declaration

标签: kotlin generics lambda interface receiver


【解决方案1】:

在 Kotlin 中,您根本无法(据我所知)在覆盖时更改参数类型,因此您也无法以这种特殊方式更改它们。

你可以做的是将接收器类型变成另一个类型参数:

interface WebhookEventInterface<T, out W : WebhookEventInterface<T, W>> {
    operator fun invoke(block: W.() -> Unit) { ... }
}

interface PushPullRequestFeatures<T> : WebhookEventInterface<T, PushPullRequestFeatures<T>> {
    override operator fun invoke(block: PushPullRequestFeatures<T>.() -> Unit) { ... }
}

(如果您不使用override,则接收器类型无论如何都会是PushPullRequestFeatures&lt;T&gt;,因为这正是W 所在的位置。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-19
    • 1970-01-01
    相关资源
    最近更新 更多