Почему Kotlin не может вывести следующий аргумент лямбда (после преобразования Java -> Kotlin)?

У меня был следующий код Java:

public class DatabaseManager { public interface Predicate<T> { boolean test(T t); } private interface Consumer<T> { void apply(T t); } private void updateLiveLists() { updateLiveLists(liveList -> true); } private void updateLiveLists(Predicate<MutableLiveList<?>> predicate) { forEachLiveList(liveList -> { if (predicate.test(liveList)) { refresh(liveList); } }); } private void forEachLiveList(Consumer<MutableLiveList<?>> consumer) { ... } 

Затем я использовал Java -> Kotlin conversion в Android Studio:

 class DatabaseManager { interface Predicate<T> { fun test(t: T): Boolean } private interface Consumer<T> { fun apply(t: T) } private fun updateLiveLists(predicate: Predicate<MutableLiveList<*>> = { liveList -> true }) { forEachLiveList({ liveList -> if (predicate.test(liveList)) { refresh(liveList) } }) } private fun forEachLiveList(consumer: Consumer<MutableLiveList<*>>) { ... } 

Ошибка со следующей ошибкой:

Несоответствие типов

Required: DatabaseManager.Consumer<MutableLiveList<*>>

Найдено: (???) -> Единица

Теперь мне пришлось изменить код следующим образом:

 private fun updateLiveLists(predicate: Predicate<MutableLiveList<*>> = object : Predicate<MutableLiveList<*>> { override fun test(t: MutableLiveList<*>): Boolean { return true; } }) { forEachLiveList(object : DatabaseManager.Consumer<MutableLiveList<*>> { // <--- !! override fun apply(t: MutableLiveList<*>) { if (predicate.test(t)) { refresh(t) } } }) } 

Хорошо, поэтому я должен был явно объявить этот анонимный интерфейс явным подклассом object , так как по какой-то причине Котлин не мог понять лямбда.


Если это помогает, у меня такая же проблема возникает в функции ниже:

 fun refresh(vararg tables: Table) { updateLiveLists({ liveList -> for (table in tables) { if (liveList.getTable() === table) { return@updateLiveLists true } } false }) } 

Что говорит:

Несоответствие типов:

Required: DatabaseManager.Predicate<MutableLiveList<*>>

Найденный: ??? -> Boolean

И я должен сделать это вместо этого

 fun refresh(vararg tables: Table) { updateLiveLists(object: DatabaseManager.Predicate<MutableLiveList<*>> { // <-- override fun test(t: MutableLiveList<*>): Boolean { for (table in tables) { if (t.getTable() === table) { return true } } return false } }) } 

Почему, и как я могу избежать этого? Как я могу использовать свой собственный Predicate / Consumer без Kotlin, путаясь о лямбда-типе?

Благодаря /u/lupajz теперь я знаю, что проблема в том, что интерфейсы, определенные в Kotlin, не преобразуются преобразованием SAM из-за https://discuss.kotlinlang.org/t/kotlin-and-sam-interface-with-two – параметров / 293/5

В основном это сводится к

«зачем вам это делать, когда вы можете использовать функциональные интерфейсы Kotlin и псевдонимы типов, если вам это нужно, тогда определите интерфейсы в Java».


Существует несколько обходных решений:

1.) встроенные объекты (что я показал выше как часть вопроса)

2.) псевдонимы типов + выставлять перегруженные методы

 private typealias KotlinPredicate<T> = (T) -> Boolean; private typealias KotlinConsumer<T> = (T) -> Unit; class DatabaseManager { private interface Consumer<T> { fun apply(t : T) : Unit; } private fun forEachLiveList(consumer: Consumer<MutableLiveList<*>>) { forEachLiveList({ consumer.apply(it) }) } private fun forEachLiveList(consumer: KotlinConsumer<MutableLiveList<*>>) { ... } 

а также

 interface Predicate<T> { fun test(t : T) : Boolean; } fun updateLiveLists(predicate: Predicate<MutableLiveList<*>>) { updateLiveLists({ predicate.test(it) }) } fun updateLiveLists(predicate: KotlinPredicate<MutableLiveList<*>> = { liveList -> true }) { forEachLiveList({ liveList -> if (predicate.invoke(liveList)) { refresh(liveList) } }) }