Ссылки функций и лямбда

Я сталкиваюсь с ошибкой компиляции при попытке использовать ссылки 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. Что касается вашего второго вопроса - эта функция еще не поддерживается.