首页 > 解决方案 > 将具体的泛型类型转换为具有 Any 上限的非 null

问题描述

我正在尝试使用具体的类型参数来检查类型参数是否可为空,并根据类型参数的可空性返回不同的类实现。这很好用,除了非空子类要求其泛型类型具有非空Any上限,以便具有KClass<T>构造函数参数。

此代码按预期工作:

interface Test
class NullableT<T> : Test
class NonNullT<T> : Test

inline fun <reified T> test(): Test {
    return if (null is T) {
        NullableT<T>()
    } else {
        NonNullT<T>()
    }
}

test<String?>()::class.simpleName // NullableT
test<String>()::class.simpleName  // NonNullT

但是,此代码存在编译器错误:

interface Test
class NullableT<T> : Test
class NonNullT<T : Any>(tClass: KClass<T>) : Test

inline fun <reified T> test(): Test {
    return if (null is T) {
        NullableT<T>()
    } else {
        NonNullT<T>(T::class) // <-- error with <T>
        // Type argument is not within its bounds. Expected: Any Found: T
    }
}

在检查 之后!(null is T),需要有某种方法可以将其转换T为具有非空Any上限。

可以将非 null 设为T可选。这有效:

interface Test
class NullableT<T> : Test
class NonNullT<T : Any> : Test

inline fun <reified T : Any> test(nullable: Boolean): Test {
    return if (nullable) {
        NullableT<T?>()
    } else {
        NonNullT<T>()
    }
}

test<String>(true)::class.simpleName // NullableT
test<String>(false)::class.simpleName // NonNullT

但我需要一种方法来使可空的T非空。这是无效的:

interface Test
class NullableT<T> : Test
class NonNullT<T : Any> : Test

inline fun <reified T> test(nullable: Boolean): Test {
    return if (nullable) {
        NullableT<T>()
    } else {
        NonNullT<T!!>() // Type parameter 'T' is not an expression
    }
}

标签: kotlingenericscastingkotlin-reified-type-parameters

解决方案


有效:

import kotlin.reflect.*
interface Test
class NullableT<T> : Test
class NonNullT<T : Any>(tClass: KClass<T>) : Test

inline fun <reified T> test(dummy: Nothing? = null): Test {
    return NullableT<T>()
}
inline fun <reified T: Any> test(): Test {
    return NonNullT<T>(T::class)
}


fun main(){
    println(test<Any>().toString())
    println(test<Any?>().toString())
    println(test<String>().toString())
    println(test<String?>().toString())
}

“但为什么这行得通?” 我听到你在问。很简单,这里发生的事情是 Kotlin 编译器更喜欢与传入参数数量匹配的函数(在本例中为 0),而不是具有默认参数的函数,这将导致允许传入参数的数量(换句话说,如果您调用带有 1 个参数的函数,编译器将更喜欢带有 1 个参数的函数,而不是带有 2 个参数的函数,其中第二个参数具有默认值)。但是,由于 T 在 2 个函数中具有不同的上限,如果您尝试调用的类型test不遵循首选函数的上限(在这种情况下是返回的函数NonNullT),则编译器将回退到调用更广泛的test函数(即NullableT)。这个解决方案有点老套,但遗憾的是我认为没有其他方法可以实现它。


推荐阅读