【问题标题】:Why cannot Kotlin infer the following lambda argument (after Java -> Kotlin conversion)?为什么 Kotlin 不能推断以下 lambda 参数(在 Java -> Kotlin 转换之后)?
【发布时间】:2018-03-25 13:10:55
【问题描述】:

我有以下 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 -&gt; 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&lt;MutableLiveList&lt;*&gt;&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&lt;MutableLiveList&lt;*&gt;&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
        }
    })
}

为什么,我怎样才能避免这种情况?如何使用我自己的 Predicate/Consumer 而不会让 Kotlin 对 lambda 类型感到困惑?

【问题讨论】:

  • 这是我今天看到的最短的问题)
  • 我想你可以在这里找到答案stackoverflow.com/questions/43235423/…
  • @DimaKozhevin 有点长,因为我发布了 2 个发生故障的示例。
  • @JemoMgebrishvili 所以它说我需要像上面那样使用object :,或者将这些接口更改为Kotlin 的函数类型的typealias,或者直接使用Kotlin 的函数类型?仅当我将使用它的所有代码也更改为 Kotlin 时,更改为 typealias 或 Kotlin 类型才有效。嗯...是的,这一个非常相关的问题。
  • @EpicPandaForce,或者您可以将功能接口留在 Java 中并在 Kotlin 中实现它们。至少我认为在链接的答案中暗示了这一点。

标签: java android lambda kotlin


【解决方案1】:

感谢/u/lupajz 我现在知道问题是在Kotlin 中定义的接口没有被SAM 转换转换,因为https://discuss.kotlinlang.org/t/kotlin-and-sam-interface-with-two-parameters/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)
        }
    })
}

【讨论】:

    猜你喜欢
    • 2022-11-22
    • 2020-01-17
    • 2019-02-16
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多