Делегирование функциональных переменных в Котлине с помощью универсального класса

В настоящее время я работаю над приложением, которое требует делегирования функциональных переменных. При попытке сделать это я столкнулся с некоторыми проблемами. Вот код минимального воспроизводимого примера:

package org.prismsus.tank

import kotlin.reflect.KProperty
fun addFunc(a : Int, b : Int) : Int {
    return a + b
}

class Test{
    inner class PrintFuncCall1{
        operator fun getValue(thisRef: Any?, property: KProperty<*>): (Int, Int) -> Int {
            fun temp(a : Int, b : Int) : Int {
                println("Function ${property.name}")
                return addFunc(a, b)
            }
            return ::temp
        }
    }
    val delegatedFun1 : (Int, Int) -> Int by PrintFuncCall1()


    inner class PrintFuncCall2<F : (Array<out Any>) -> R, R>{
        operator fun getValue(thisRef : Any?, property : KProperty<*>) : (Array<out Any>) -> R{
            fun temp(vararg params : Any) : R{
                println("Function ${property.name}")
                println("Params: ${params.joinToString()}")
                return addFunc(params[0] as Int, params[1] as Int) as R
            }
            return ::temp
        }
    }

    val delegatedFun2 : (Int, Int) -> Int by PrintFuncCall2()
}

fun main(){
    val test = Test()
    println(test.delegatedFun1(1, 2))
    println(test.delegatedFun2(3, 4))
}

Здесь delegatedFun1 и PrintFuncCall1 сработали нормально. Однако я попытался изменить класс делегата на универсальный класс и обнаружил, что это не сработало. В частности, я получил эту ошибку компиляции для delegatedFun2 и PrintFuncCall2:

Property delegate must have a 'getValue(Test, KProperty<*>)' method. None of the following functions is suitable: 
public final operator fun getValue(thisRef: Any?, property: KProperty<*>): (Array<out Any>) -> ??? defined in org.prismsus.tank.Test.PrintFuncCall2

Я не совсем понимаю, почему getValue требует, чтобы thisRef принадлежал к типу Test, который является типом более крупного класса. Это особенно странно, поскольку я делегирую переменную типа (Int, Int) -> Int. Далее, даже если я попытался изменить подпись getValue на getValue(thisRef : Test, property : KProperty<*>), я получил следующую ошибку:

Property delegate must have a 'getValue(Test, KProperty<*>)' method. None of the following functions is suitable: 
public final operator fun getValue(thisRef: Test, property: KProperty<*>): (Array<out Any>) -> ??? defined in org.prismsus.tank.Test.PrintFuncCall2

Помимо этого, у меня есть небольшой вопрос о механизме ограничения Kotlin типа параметров. Мое намерение использовать PrintFuncCall2 — отметить F как тип функции, а R как возвращаемое значение функции F. Однако при изменении подписи getValue с getValue(thisRef : Test, property : KProperty<*>) : (Array<out Any>) -> R на getValue(thisRef : Test, property : KProperty<*>) : F я получил это сообщение от IDE на строке return ::temp:

Required:
KFunction1<Array<out Any>, R>
Found:
F

Разве это не одно и то же?

Похоже, что вы выдаете несоответствие типов между ожидаемым типом возвращаемого значения делегата и типом, который вы даете ему на уровне свойства.

Josh 30.04.2024 22:55

Предполагается, что ваш делегат возвращает функцию типа (Array<Any>) -> R, но вы аннотируете свойство с помощью (Int, Int) -> Int. Array<out Any> эквивалентно vararg Any, но НЕ означает «любую функцию с любыми параметрами».

Josh 30.04.2024 22:57

Ошибка должна исчезнуть, если аннотировать свойство следующим образом: val delegatedFun2 : (Array<Int>) -> Int by PrintFuncCall2()

Josh 30.04.2024 22:59

@Джош Спасибо за комментарий. Метод действительно сработал, но теперь мне придется вызывать делегированную функцию следующим образом: println(test.delegatedFun2(arrayOf(3, 4))). если Array<out Any> не означает «любая функция с любыми параметрами», то есть ли у меня какие-либо способы обозначить тип vararg Any для сопоставления функции со всеми видами параметров?

ttzytt 01.05.2024 04:25

@Josh Кроме того, как вы думаете, сообщение об ошибке предназначено или это ошибка? Такое сообщение об ошибке: Property delegate must have a 'getValue(Test, KProperty<*>)' method. None of the following functions is suitable: public final operator fun getValue(thisRef: Test, property: KProperty<*>): (Array<out Any>) -> ??? defined in org.prismsus.tank.Test.PrintFuncCall2 меня очень смутило, и если это действительно ошибка, я, вероятно, смогу сообщить об этом на YouTrack.

ttzytt 01.05.2024 04:27

Сообщение об ошибке немного неспецифично. Вы можете попытаться поднять это как проблему.

Josh 02.05.2024 18:18

К сожалению, невозможно аннотировать тип как функцию с любым типом или количеством параметров. Вам нужно будет использовать массив.

Josh 02.05.2024 18:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что вы выдаете несоответствие типов между ожидаемым типом возвращаемого значения делегата и типом, который вы даете ему на уровне свойства.

Предполагается, что ваш делегат возвращает функцию типа (Array<Any>) -> R, но вы аннотируете свойство с помощью (Int, Int) -> Int. Array<out Any> эквивалентно vararg Any, но НЕ означает «любую функцию с любыми параметрами».

Ошибка должна исчезнуть, если аннотировать свойство следующим образом:

val delegatedFun2: (Array<Int>) -> Int by PrintFuncCall2()

К сожалению, невозможно аннотировать тип как функцию с любым типом или количеством параметров. Вам нужно будет использовать массив.

Другие вопросы по теме