为啥 Kotlin 不能推断以下 lambda 参数(在 Java -> Kotlin 转换之后)?
Posted
技术标签:
【中文标题】为啥 Kotlin 不能推断以下 lambda 参数(在 Java -> Kotlin 转换之后)?【英文标题】: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 -> 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<*>>
找到:(???) -> 单位
现在我不得不将代码更改为:
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<*>>
找到:??? -> 布尔值
而我必须这样做
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 类型感到困惑?
【问题讨论】:
这是我今天看到的最短的问题) 我想你可以在这里找到答案***.com/questions/43235423/… @DimaKozhevin 有点长,因为我发布了 2 个发生故障的示例。 @JemoMgebrishvili 所以它说我需要像上面那样使用object :
,或者将这些接口更改为Kotlin 的函数类型的typealias
,或者直接使用Kotlin 的函数类型?仅当我将使用它的所有代码也更改为 Kotlin 时,更改为 typealias
或 Kotlin 类型才有效。嗯...是的,这是一个非常相关的问题。
@EpicPandaForce,或者您可以将功能接口留在 Java 中并在 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)
)
【讨论】:
以上是关于为啥 Kotlin 不能推断以下 lambda 参数(在 Java -> Kotlin 转换之后)?的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin函数 ⑤ ( 匿名函数变量类型推断 | 匿名函数参数类型自动推断 | 匿名函数又称为 Lambda 表达式 )