generics - 对 Kotlin 何时推断平台类型感到困惑

标签 generics kotlin android-livedata kotlin-reified-type-parameters

摆弄以下示例代码让我意识到我对 Kotlin 何时推断平台类型感到困惑:

inline fun <reified U, V> LiveData<U>.map(crossinline f: (U) -> V): LiveData<V> {
    val result = MediatorLiveData<V>()
    result.addSource(this) { u -> // u: U!
        if (u is U) {
            result.value = f(u)
        }
    }
    return result
}

val x = MutableLiveData<Int>()
val y = x.map { it + 1 }

x.value = 1 // ok
x.value = null // will eventually crash from doing null + 1

我希望 reified+crossinline 的使用能够防止 map调用 f 的函数当unull ,因为它会检查是否 null is Int 。但有趣的是,null偷偷溜过支票。

我想我一定是误解了 reified+crossinline 的工作原理,但似乎真正的问题是类型推断: U似乎被推断为Int! ,不是Int 。例如,手动指定 map的类型参数使事情正常工作:

val y = x.map<Int, Int> { it + 1 }

所以。为什么 Kotlin 会推断出上面的平台类型? (毕竟, x 推断出类型 MutableLiveData<Int> ,而不是 MutableLiveData<Int!> 。)除了自己进行推断之外,还有没有办法不推断平台类型?

最佳答案

在深入了解 Kotlin 的复杂性(例如具体化泛型)之前,您应该问的第一个问题是:为什么我可以这样做?

val x = MutableLiveData<Int>()
x.value = null 

这个问题的答案源于这样一个事实:MutableLiveData 是用 Java 编写的,而不是 Kotlin。

如果你用 Kotlin 编写这个类:

class MyKotlinClass<T: Any> {
    lateinit var value: T
}

然后尝试这样做:

val x = MyKotlinClass<Int>()
x.value = null

那么它就无法编译。这是因为您已将类型定义为不可为 null 的 Any

但是想象一下,用 Java 编写这样一个泛型类,其中 AnyObject,并且除了提供注释之外,您实际上无法定义任何内容的可空性:

class ExampleJavaClass<T> {
    public ExampleJavaClass(T param) {

    }

    static ExampleJavaClass getStringInstance() {
        return new ExampleJavaClass<String>(null);
    }
}

这是允许的。因此,为了允许与 Java 完全兼容的互操作,Kotlin 必须假设 null 是可以的。不幸的是,对你来说,它是不可见的。

除非有人生成了 LiveData 的 Kotlin 特定实现来加强这一点,否则您必须处理 null,或者您可以自己编写一个,例如 this 。我不一定鼓励您自己编写 - 可能会产生不利后果。

在许多情况下,如果您拥有 Java 代码,则可以通过注释 Java 来定义可空性来改善互操作情况,例如@NonNull。但是,您似乎无法使用类型参数上的现有注释来执行此操作。

关于generics - 对 Kotlin 何时推断平台类型感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58580915/

相关文章:

android - 无法从edittext获取数据,Android Kotlin

android - StaggeredGridLayoutManager 正在加载左侧的一项,其余的加载右侧

android - 如何在 android 中使用房间数据库更改 LiveData 可观察查询参数?

android - 可空性和使用 Kotlin 的 LiveData

swift - 我可以使一个结构或类多次符合通用协议(protocol)吗?

c# - 通用约束,其中 T : struct and where T : class

c# - 通用扩展方法 C#

Java 通用可序列化、可迭代堆栈

kotlin - 为什么这个 Kotlin 对象可以继承自自身?

android - 异步 LiveData/Room 查询会导致竞争条件吗?