如何在 Kotlin 中获取 KType?
How to obtain a KType in Kotlin?
我正在试验 Kotlin 中的反射功能,但我似乎无法理解如何获取 KType 值。
假设我有一个 class 将短语映射到对象工厂。如果出现歧义,用户可以提供一个 type
参数,将搜索范围缩小到 return 那种类型的对象(或某些子类型)的工厂。
fun mapToFactory(phrase: Phrase,
type: KType = Any::class): Any {...}
type
需要接受几乎任何东西,包括 Int
,根据我的经验,它似乎被特殊对待。默认情况下,它应该类似于 Any
,这意味着 "do not exclude any factories".
如何为 type
分配默认值(或任何值)?
根据您的描述,听起来您的函数应该采用 KClass
参数,而不是 KType
,并使用 isSubclass
而不是 isSubtype
检查传入的对象。
类型(由 kotlin-reflect
中的 KType
表示)通常来自代码中声明的签名;它们表示一组广泛的值,函数将这些值作为参数或 return。类型由 class、该 class 的通用参数和可空性组成。 JVM 运行时类型的问题在于,由于擦除,无法确定泛型 class 变量的确切类型。例如,如果您有一个列表,则无法在运行时确定该列表的通用类型,即您无法区分 List<String>
和 List<Throwable>
。
不过,要回答您最初的问题,您可以使用 createType()
:
从 KClass
创建一个 KType
val type: KType = Any::class.createType()
请注意,如果 class 是泛型,则需要传递泛型参数的类型投影。在简单的情况下(所有类型变量都可以用星形投影代替),starProjectedType
也可以。有关 createType
和 starProjectedType
、.
的更多信息
从Kotlin 1.3.40开始,可以使用实验函数typeOf<T>()
获取任意类型的KType
:
val int: KType = typeOf<Int>()
与T::class.createType()
相反,它支持嵌套的泛型参数:
val listOfString: KType = typeOf<List<String>>()
typeOf<T>()
函数在您想从具体化类型参数中获取 KType
时特别有用:
inline fun <reified T> printType() {
val type = typeOf<T>()
println(type.toString())
}
用法示例:
fun main(args: Array<String>) {
printType<Map<Int, String>>()
// prints: kotlin.collections.Map<kotlin.Int, kotlin.String>
}
由于此功能仍处于实验状态,您需要在使用 typeOf<T>()
的函数周围选择加入 @UseExperimental(ExperimentalStdlibApi::class)
。随着功能变得更加稳定(可能在 Kotlin 1.4 中),这可以省略。此外,目前它仅适用于 Kotlin/JVM,不适用于 Kotlin/Native 或 Kotlin/JS。
另请参阅:
- Release announcement
- API Doc(目前非常稀少)
我正在试验 Kotlin 中的反射功能,但我似乎无法理解如何获取 KType 值。
假设我有一个 class 将短语映射到对象工厂。如果出现歧义,用户可以提供一个 type
参数,将搜索范围缩小到 return 那种类型的对象(或某些子类型)的工厂。
fun mapToFactory(phrase: Phrase,
type: KType = Any::class): Any {...}
type
需要接受几乎任何东西,包括 Int
,根据我的经验,它似乎被特殊对待。默认情况下,它应该类似于 Any
,这意味着 "do not exclude any factories".
如何为 type
分配默认值(或任何值)?
根据您的描述,听起来您的函数应该采用 KClass
参数,而不是 KType
,并使用 isSubclass
而不是 isSubtype
检查传入的对象。
类型(由 kotlin-reflect
中的 KType
表示)通常来自代码中声明的签名;它们表示一组广泛的值,函数将这些值作为参数或 return。类型由 class、该 class 的通用参数和可空性组成。 JVM 运行时类型的问题在于,由于擦除,无法确定泛型 class 变量的确切类型。例如,如果您有一个列表,则无法在运行时确定该列表的通用类型,即您无法区分 List<String>
和 List<Throwable>
。
不过,要回答您最初的问题,您可以使用 createType()
:
KClass
创建一个 KType
val type: KType = Any::class.createType()
请注意,如果 class 是泛型,则需要传递泛型参数的类型投影。在简单的情况下(所有类型变量都可以用星形投影代替),starProjectedType
也可以。有关 createType
和 starProjectedType
、
从Kotlin 1.3.40开始,可以使用实验函数typeOf<T>()
获取任意类型的KType
:
val int: KType = typeOf<Int>()
与T::class.createType()
相反,它支持嵌套的泛型参数:
val listOfString: KType = typeOf<List<String>>()
typeOf<T>()
函数在您想从具体化类型参数中获取 KType
时特别有用:
inline fun <reified T> printType() {
val type = typeOf<T>()
println(type.toString())
}
用法示例:
fun main(args: Array<String>) {
printType<Map<Int, String>>()
// prints: kotlin.collections.Map<kotlin.Int, kotlin.String>
}
由于此功能仍处于实验状态,您需要在使用 typeOf<T>()
的函数周围选择加入 @UseExperimental(ExperimentalStdlibApi::class)
。随着功能变得更加稳定(可能在 Kotlin 1.4 中),这可以省略。此外,目前它仅适用于 Kotlin/JVM,不适用于 Kotlin/Native 或 Kotlin/JS。
另请参阅:
- Release announcement
- API Doc(目前非常稀少)