首页 > 解决方案 > 如何处理泛型类中的可为空类型

问题描述

我想在 kotlin 中写一个 Promise 类。此类使用泛型类型。该类型也可以是可为空的类型。当我调用消费者时,如果通用类型可以为空,则该值可以为空。如果不是,则必须将值设置为对象。kotlin 编译器向我显示以下消息: 智能转换为 'T' 是不可能的,因为 'value' 是一个可变属性,此时可能已更改

我理解为什么会出现此消息,但我确信此时该值必须是正确的。我怎样才能编译这个类?我试图用!!强制访问该值 但随后我的null测试将因 NPE 而失败。

java.lang.NullPointerException
    at test.Promise.resolve(App.kt:20)
    at test.AppTest.testPromiseNull(AppTest.kt:31)
class Promise<R> {

    private var resolved = false

    private var value: R? = null

    var then: Consumer<R>? = null

    fun resolve(r: R) = synchronized(this) {
        if (resolved) error("Promise already resolved!")
        value = r
        resolved = true
        then?.accept(value) // Smart cast to 'T' is impossible, because 'value' is a mutable property that could have been changed by this time*
    }

    fun then(consumer: Consumer<R>) = synchronized(this) {
        if (then != null) error("Just one consumer is allowed!")
        then = consumer
        val value = value
        if (resolved) {
            consumer.accept(value) // Smart cast to 'T' is impossible, because 'value' is a mutable property that could have been changed by this time*
        }
    }
}
@Test fun testPromise() {
    val promise = Promise<String>()
    var resolved = false
    promise.then {
        assertEquals(it,  "hello" )
        resolved = true
    }
    promise.resolve("hello")
    assert(resolved)
}


@Test fun testPromiseNull() {
    val promise = Promise<String?>()
    var resolved = false
    promise.then {
        assertNull(it)
        resolved = true
    }
    promise.resolve(null)
    assert(resolved)
}

更新 我创建了一个小帮助功能

private fun <T> uncheckedCast(t: T?): T {
    @Suppress("UNCHECKED_CAST")
    return t as T
}

标签: kotlingenerics

解决方案


对于您的resolve函数,您已经拥有可以使用的不可变参数值。

fun resolve(r: R) = synchronized(this) {
    if (resolved) error("Promise already resolved!")
    value = r
    resolved = true
    then?.accept(r)
}

在另一种情况下,由于您比编译器了解更多,您可以进行显式转换,并抑制警告。

fun then(consumer: Consumer<R>) = synchronized(this) {
    if (then != null) error("Just one consumer is allowed!")
    then = consumer
    if (resolved) {
        @Suppress("UNCHECKED_CAST")
        consumer.accept(value as R)
    }
}

推荐阅读