Смущающее делегирование собственности в Gradle's Kotlin DSL - PullRequest
0 голосов
/ 17 апреля 2020

Ниже приведен фрагмент кода, с которым я столкнулся в документации Gradle https://docs.gradle.org/current/userguide/tutorial_using_tasks.html

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

В приведенном выше примере привет тип TaskProvider, который предоставляет определение задачи / действие Второй вызов hello - продлить поведение задачи.

Этот делегат использование выглядит немного смущающим для меня. Ниже приведены вопросы, которые меня вызывают:

1) При проверке декомпилированного байт-кода я вижу tasks.registering возвращает RegisteringDomainObjectDelegateProviderWithAction объект, который должен использоваться как делегат и, следовательно, должны предоставить методы getValue () и setValue () для делегата для работы, но, как я видел, методы не предусмотрены. Вместо этого класс RegisteringDomainObjectDelegateProviderWithAction имеет свойство DelegateProvider типа tasks , которое должно обеспечивать делегат . Может ли кто-нибудь помочь мне понять, как здесь происходит делегирование?

2) Второй вызов должен добавить поведение в задачу hello . Поскольку hello является свойством, как мы можем передать ему лямбда / поведение? Чего мне не хватает?

Я уже видел kotlin документацию, которая дает хорошее объяснение делегатов, но не помогает понять вышеупомянутый случай https://kotlinlang.org/docs/reference/delegated-properties.html

Буду признателен за подробное объяснение, поскольку я новичок в Kotlin.

1 Ответ

1 голос
/ 17 апреля 2020
  1. Относительно использования делегата:

    Делегирование работает через метод оператора расширения provideDelegate, определенный для RegisteringDomainObjectDelegateProviderWithAction:

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

    Оператор provideDelegate допускает более сложные логики c при создании делегата. В соответствии с документами :

    Определив оператор provideDelegate, вы можете расширить логи c создания объекта, которому делегирована реализация свойства. Если объект, используемый справа от by, определяет provideDelegate как функцию-член или функцию расширения, эта функция будет вызываться для создания экземпляра делегата свойства.

  2. Относительно «передачи лямбды в свойство»:

    Это реализовано путем перегрузки оператора invoke в качестве функции расширения класса TaskProvider:

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

    По сути, вызов hello { /* your lambda */ } переводится в hello.invoke { /* your lambda */ }.

...