В настоящее время я работаю над приложением, которое требует делегирования функциональных переменных. При попытке сделать это я столкнулся с некоторыми проблемами. Вот код минимального воспроизводимого примера:
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
Разве это не одно и то же?
Предполагается, что ваш делегат возвращает функцию типа (Array<Any>) -> R
, но вы аннотируете свойство с помощью (Int, Int) -> Int
. Array<out Any>
эквивалентно vararg Any
, но НЕ означает «любую функцию с любыми параметрами».
Ошибка должна исчезнуть, если аннотировать свойство следующим образом: val delegatedFun2 : (Array<Int>) -> Int by PrintFuncCall2()
@Джош Спасибо за комментарий. Метод действительно сработал, но теперь мне придется вызывать делегированную функцию следующим образом: println(test.delegatedFun2(arrayOf(3, 4)))
. если Array<out Any>
не означает «любая функция с любыми параметрами», то есть ли у меня какие-либо способы обозначить тип vararg Any
для сопоставления функции со всеми видами параметров?
@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.
Сообщение об ошибке немного неспецифично. Вы можете попытаться поднять это как проблему.
К сожалению, невозможно аннотировать тип как функцию с любым типом или количеством параметров. Вам нужно будет использовать массив.
Похоже, что вы выдаете несоответствие типов между ожидаемым типом возвращаемого значения делегата и типом, который вы даете ему на уровне свойства.
Предполагается, что ваш делегат возвращает функцию типа (Array<Any>) -> R
, но вы аннотируете свойство с помощью (Int, Int) -> Int
. Array<out Any>
эквивалентно vararg Any
, но НЕ означает «любую функцию с любыми параметрами».
Ошибка должна исчезнуть, если аннотировать свойство следующим образом:
val delegatedFun2: (Array<Int>) -> Int by PrintFuncCall2()
К сожалению, невозможно аннотировать тип как функцию с любым типом или количеством параметров. Вам нужно будет использовать массив.
Похоже, что вы выдаете несоответствие типов между ожидаемым типом возвращаемого значения делегата и типом, который вы даете ему на уровне свойства.