【问题标题】:Confusing Property Delegation in Gradle's Kotlin DSLGradle 的 Kotlin DSL 中令人困惑的属性委托
【发布时间】:2020-04-17 17:39:29
【问题描述】:

下面是我在 gradle 的文档中遇到的代码 sn-p https://docs.gradle.org/current/userguide/tutorial_using_tasks.html

val hello by tasks.registering {
    doLast {
        println("Hello Earth")
    }
}
hello {
    doFirst {
        println("Hello Venus")
    }
}

在上面,hello 是一个提供任务定义/动作的TaskProvider 类型。对 hello 的第二个调用是扩展任务的行为。

这个 delegate 用法让我有点困惑。以下是困扰我的问题:

1) 在检查反编译的字节码时,我看到 tasks.registering 返回应该用作委托的 RegisteringDomainObjectDelegateProviderWithAction 对象,因此应该提供 getValue() 和delegate 的 setValue() 方法可以工作,但正如我所见,没有提供方法。相反,类 RegisteringDomainObjectDelegateProviderWithAction 有一个 tasks 类型的 delegateProvider 属性,它应该提供 delegate。谁能帮我理解一下,这里的委托是如何工作的?

2) 第二次调用应该为 hello 任务添加行为。由于 hello 是一个属性,我们如何能够将 lambda/行为传递给它?我错过了什么?

我已经看过 kotlin 文档,它很好地解释了代表,但无助于理解上述案例 https://kotlinlang.org/docs/reference/delegated-properties.html

由于我是 Kotlin 的新手,因此希望得到详细的解释。

【问题讨论】:

标签: kotlin gradle gradle-kotlin-dsl


【解决方案1】:
  1. 关于委托使用:

    委托通过RegisteringDomainObjectDelegateProviderWithAction上定义的扩展运算符方法provideDelegate工作:

    operator fun RegisteringDomainObjectDelegateProviderWithAction<out TaskContainer, Task>.provideDelegate(
        receiver: Any?,
        property: KProperty<*>
    ) = ExistingDomainObjectDelegate.of(
        delegateProvider.register(property.name, action)
    )
    

    provideDelegate 运算符允许在委托创建中实现更复杂的逻辑。根据docs

    通过定义provideDelegate 运算符,您可以扩展创建委托属性实现的对象的逻辑。如果 by 右侧使用的对象将 provideDelegate 定义为成员或扩展函数,则将调用该函数来创建属性委托实例。

  2. 关于“将 lambda 传递给属性”:

    这是通过将invoke operator 重载为TaskProvider 类的扩展函数来实现的:

    operator fun <T> NamedDomainObjectProvider<T>.invoke(action: T.() -> Unit) =
        configure(action)
    

    基本上,调用hello { /* your lambda */ } 被脱糖为hello.invoke { /* your lambda */ }

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    相关资源
    最近更新 更多