【问题标题】:Confused about when Kotlin infers a platform type对 Kotlin 何时推断平台类型感到困惑
【发布时间】:2019-10-27 15:46:33
【问题描述】:

弄乱以下示例代码让我意识到我对 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

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

    在您接近 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
    

    那么它不会编译。那是因为您已将类型定义为不可为空的 Any

    但是想象一下在 Java 中编写这样一个泛型类,其中 AnyObject 并且你不能真正定义任何东西的可空性,除非通过提供注释:

    class ExampleJavaClass<T> {
        public ExampleJavaClass(T param) {
    
        }
    
        static ExampleJavaClass getStringInstance() {
            return new ExampleJavaClass<String>(null);
        }
    }
    

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

    直到有人产生了一个特定于 Kotlin 的 LiveData 实现来加强这一点,你必须处理 null,或者你可以自己写一个,比如 this。我不一定鼓励自己编写 - 可能会产生不良后果。

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

    【讨论】:

    • 关于“平台类型”一词,我认为是官方的:kotlinlang.org/docs/reference/…
    • 啊,好吧,我不知道这是一个官方术语,并认为您可能指的是 Android 或其他什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-09
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多