【问题标题】:How to handle nullable types in generic class如何处理泛型类中的可为空类型
【发布时间】:2021-02-05 21:53:41
【问题描述】:

我想在 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
}

【问题讨论】:

    标签: kotlin generics


    【解决方案1】:

    对于您的 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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-25
      • 1970-01-01
      • 2018-11-27
      • 2017-06-25
      • 2020-09-21
      • 1970-01-01
      • 2019-06-12
      • 2018-09-29
      • 2023-03-15
      相关资源
      最近更新 更多