How to obtain a KType in Kotlin?

北慕城南 提交于 2019-12-23 19:06:18

问题


I'm experimenting with the reflection functionality in Kotlin, but I can't seem to understand how to obtain a KType value.

Suppose I have a class that maps phrases to object factories. In case of ambiguity, the user can supply a type parameter that narrows the search to only factories that return that type of object (or some sub-type).

fun mapToFactory(phrase: Phrase,
          type: KType = Any::class): Any {...}

type needs to accept just about anything, including Int, which from my experience seems to be treated somewhat specially. By default, it should be something like Any, which means "do not exclude any factories".

How do I assign a default value (or any value) to type?


回答1:


From your description, sounds like your function should take a KClass parameter, not a KType, and check the incoming objects with isSubclass, not isSubtype.

Types (represented by KType in kotlin-reflect) usually come from signatures of declarations in your code; they denote a broad set of values which functions take as parameters or return. A type consists of the class, generic arguments to that class, and nullability. The problem with types at runtime on JVM is that because of erasure, it's impossible to determine the exact type of a variable of a generic class. For example if you have a list, you cannot determine the generic type of that list at runtime, i.e. you cannot differentiate between List<String> and List<Throwable>.

To answer your initial question though, you can create a KType out of a KClass with createType():

val type: KType = Any::class.createType()

Note that if the class is generic, you need to pass type projections of generic arguments. In simple cases (all type variables can be replaced with star projections), starProjectedType will also work. For more info on createType and starProjectedType, see this answer.




回答2:


Since Kotlin 1.3.40, you can use the experimental function typeOf<T>() to obtain the KType of any type:

val int: KType = typeOf<Int>()

In contrast to T::class.createType(), this supports nested generic arguments:

val listOfString: KType = typeOf<List<String>>()

The typeOf<T>() function is particularly useful when you want to obtain a KType from a reified type parameter:

inline fun <reified T> printType() {
    val type = typeOf<T>()
    println(type.toString())
}

Example usage:

fun main(args: Array<String>) {
    printType<Map<Int, String>>()
    // prints:   kotlin.collections.Map<kotlin.Int, kotlin.String>
}

Since this feature is still in experimental status, you need to opt-in with @UseExperimental(ExperimentalStdlibApi::class) around your function that uses typeOf<T>(). As the feature becomes more stable (possibly in Kotlin 1.4), this can be omitted. Also, at this time it is only available for Kotlin/JVM, not Kotlin/Native or Kotlin/JS.

See also:

  • Release announcement
  • API Doc (very sparse currently)


来源:https://stackoverflow.com/questions/42862966/how-to-obtain-a-ktype-in-kotlin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!