Ссылки функций и лямбда
Я сталкиваюсь с ошибкой компиляции при попытке использовать ссылки lambdas/function с kotlin:
class Foo {
fun getFilteredList(){
val numbers = listOf(1, 2, 3)
numbers.filter(::isOdd) // prints [1, 3]
}
fun isOdd(x: Int): Boolean = x % 2 != 0
}
Но я получаю ошибку времени компиляции, говоря о несоответствии типа:
Ошибка: (18, 16) Gradle: ошибка ввода типа: встроенная забава kotlin.Iterable.filter(предикат: (T) → kotlin.Boolean): kotlin.List нельзя применить к получателю: kotlin.List Аргументы: (kotlin.reflect.KFunction2) Ошибка: (18, 23) Gradle: Несоответствие типов: предполагаемый тип это kotlin.reflect.KFunction2, но (kotlin.Int) → ??? ожидалось Ошибка: (18, 23) Gradle: несоответствие типов: выведенный тип - kotlin.reflect.KFunction2 но (kotlin.Int) → kotlin.Boolean ожидалось Ошибка: (18, 25) Gradle: левая сторона вызываемой ссылки с параметр приемника не может быть пустым. Укажите тип приемник до '::' явно
Я не уверен, что такое ошибка, и какой тип я должен явно указывать перед '::'
Другой вопрос:
Могу ли я использовать другую функцию объектов в качестве ссылки в котлин? Что-то вроде этого:
class Bar {
fun isOdd(x: Int): Boolean = x % 2 != 0
}
class Foo {
fun getFilteredList(){
val bar = Bar()
val numbers = listOf(1, 2, 3)
numbers.filter(bar::isOdd) // Use Bar method
}
}
Ответы
Ответ 1
Во втором примере: да, с помощью Kotlin 1.1 поддерживается ссылка связанной функции, поэтому вы можете написать bar::isOdd
аналогично Java.
В первом примере ошибка пытается сказать, что isOdd
на самом деле является функцией двух параметров (типов Foo
и Int
) и передачи функции, принимающей два параметра в качестве аргумента, тип которого функция одного параметра не допускается. Чтобы скомпилировать пример, вы можете сделать isOdd
верхнюю или локальную функцию, которая сделает ее функцией одного параметра типа Int
. Или, если вы используете Kotlin 1.1+, используйте ссылочный синтаксис связанной функции и просто напишите this::isOdd
.
Ответ 2
Это смешно. "Java ударяет". Ха-ха
Ваша проблема проста: вы объявили isOdd
в классе Foo
, правильно? Тогда это не функция, а метод. Это означает, что для этого требуется экземпляр Foo
(ссылка this
), поэтому он является функцией из двух параметров: Foo.(Int) -> Boolean
. И синтаксическая ошибка показывает, что ссылка на метод выглядит как Foo::isOdd
.
В любом случае объявление нестатического метода, который не использует объект, является антипаттерном даже в Java, не согласны ли вы?
Проблема может быть решена путем объявления свободной функции без класса или путем ее расширения: fun Int.isOdd()
P.S. Что касается вашего второго вопроса - эта функция еще не поддерживается.