Kotlin的反思:未知类型参数 [英] Kotlin's reflection : Unknown type parameter
问题描述
我正在对科特林的倒影进行一些实验.
I am running some experiments on Kotlin's reflection.
我正在尝试使用其参数获取泛型类的反射对象.
I am trying to get a reflection object of a generic class with its argument.
在Java中,这将是ParameterizedType
.
In Java, that would be a ParameterizedType
.
使用Java的反射API来获取此类信息的方法有些复杂:创建泛型类的匿名子类,然后获取其超类型的第一个参数.
The way to get such a thing using Java's reflection API is a bit convoluted: create an anonymous subclass of a generic class, then get its super-type first parameter.
这是一个例子:
@Suppress("unused") @PublishedApi
internal abstract class TypeReference<T> {}
inline fun <reified T> jGeneric() =
((object : TypeReference<T>() {}).javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
当我println(jGeneric<List<String?>>())
时,它会打印java.util.List<? extends java.lang.String>
,考虑到Kotlin的List
使用声明站点out
的变化且Java类型没有可空性的概念,这是合乎逻辑的.
When I println(jGeneric<List<String?>>())
, it prints java.util.List<? extends java.lang.String>
, which is logical considering that Kotlin's List
uses declaration-site out
variance and that Java types have no notion of nullability.
现在,我想获得相同的结果,但是要使用Kotlin反射API(当然,其中将包含可空性信息).
Now, I would like to achieve the same kind of result, but with the Kotlin reflection API (that would, of course, contain nullability information).
当然,List<String>::class
无法工作,因为它会产生KClass
.而我正在寻找KType
.
Of course, List<String>::class
cannot work since it yields a KClass
. and I am looking for a KType
.
但是,当我尝试此操作时:
However, when I try this:
inline fun <reified T> kGeneric() =
(object : TypeReference<T>() {})::class.supertypes[0].arguments[0].type
当我println(kGeneric<List<String?>>())
时,它会打印[ERROR : Unknown type parameter 0]
,这很...嗯,反斜杠;)
When I println(kGeneric<List<String?>>())
, it prints [ERROR : Unknown type parameter 0]
, which is quite... well, anticlimactic ;)
如何在Kotlin中获得反映List<String>
的KType
?
How can I get, in Kotlin, a KType
reflecting List<String>
?
推荐答案
要在Kotlin 1.1中创建KType
实例,您有两个选择:
To create a KType
instance in Kotlin 1.1, you have two options:
-
要从
KClass
中创建简单的非空类型,其中该类不是通用的,或者可以将所有类型参数替换为星形投影(*
),请使用starProjectedType
财产.例如,下面的代码创建一个KType
表示一个不可为null的类型String
:
To create a simple non-nullable type out of a
KClass
, where the class is either not generic or you can substitute all its type parameters with star projections (*
), use thestarProjectedType
property. For example, the following creates aKType
representing a non-nullable typeString
:
val nonNullStringType = String::class.starProjectedType
或者,下面的代码创建一个KType
表示一个不可为空的类型List<*>
:
Or, the following creates a KType
representing a non-nullable type List<*>
:
val nonNullListOfSmth = List::class.starProjectedType
对于更复杂的情况,请使用createType
函数.它需要类,类型参数以及类型是否应为可为空.类型参数是KTypeProjection
的列表,它只是类型+差异(输入/输出/无).例如,以下代码创建一个表示List<String>
的KType
实例:
For more complex cases, use the createType
function. It takes the class, type arguments and whether or not the type should be nullable. Type arguments are a list of KTypeProjection
which is simply a type + variance (in/out/none). For example, the following code creates a KType
instance representing List<String>
:
val nonNullStringType = String::class.starProjectedType
val projection = KTypeProjection.invariant(nonNullStringType)
val listOfStrings = listClass.createType(listOf(projection))
或者,以下创建类型List<String>?
:
val listOfStrings = listClass.createType(listOf(projection), nullable = true)
starProjectedType
和createType
都在包kotlin.reflect.full
中定义.
我们正在计划以介绍简单地获取KType
实例的可能性从内联函数的修饰类型参数中获得帮助,这在某些情况下可以静态地知道所需的类型,但是目前尚不清楚是否有可能在没有较大开销的情况下实现.因此,在实施之前,请使用上面说明的声明.
We're planning to introduce the possibility of getting a KType
instance simply from a reified type parameter of an inline function which would help in some cases where the needed type is known statically, however currently it's not entirely clear if that's possible without major overhead. So, until that's implemented, please use the declarations explained above.
这篇关于Kotlin的反思:未知类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!