kotlin - 将具体的泛型类型转换为具有 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
}
}
解决方案
这有效:
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
)。这个解决方案有点老套,但遗憾的是我认为没有其他方法可以实现它。
推荐阅读
- r - R中的随机抽样:限制重复次数
- go - 提供动态长度响应数据
- google-chrome - 为什么无法下载状态码 4XX 和 5XX 的文件
- c# - 如何使用图表 C# 编程计算 id 并按日期排序
- c# - 我在哪里可以看到 C# 中预定义方法的代码?
- azure - 如何在 azure kubernetes 集群(启用 RBAC)中为服务帐户分配权限?
- python - 此正则表达式是否失败,或者我是否需要修改正则表达式以支持“可选后跟”?
- javascript - 将 HTML 元素转换为数组并处理 null
- javascript - 如何在 Reactjs 的组件状态下使用 OOP?
- arcgis - 4.x:自定义小部件之间的通信