为什么Kotlin不能推断出以下lambda参数(在Java之后 - > Kotlin转换)?

时间:2017-10-13 11:46:19

标签: java android lambda 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) {
        ...
    }

然后我在Android Studio中使用了Java -> Kotlin conversion

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<*>>

     

找到:(???) - &gt;单元

现在我必须将代码更改为以下内容:

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的显式子类,因为无论出于什么原因,Kotlin无法弄清楚lambda。

如果有帮助,我在其下面的函数中遇到同样的问题:

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

其中说:

  

类型不匹配:

     

Required: DatabaseManager.Predicate<MutableLiveList<*>>

     

发现:??? - &GT;布尔

而我必须这样做

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
        }
    })
}

为什么,我该如何避免这种情况?如果没有Kotlin对lambda类型感到困惑,我如何使用自己的Predicate / Consumer?

1 个答案:

答案 0 :(得分:1)

感谢/u/lupajz我现在知道问题是,由于https://discuss.kotlinlang.org/t/kotlin-and-sam-interface-with-two-parameters/293/5

,Kotlin中定义的接口被SAM转换转换

基本上归结为

  

“当你可以使用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)
        }
    })
}