简体   繁体   English

Kotlin:Kotlin 中的泛型类型

[英]Kotlin: Generic types in Kotlin

To get the class definition to be used for example for json deserialization the following can be used in Kotlin:要获取要用于例如 json 反序列化的类定义,可以在 Kotlin 中使用以下内容:

Map::class.java

A example usage is the following:一个示例用法如下:

val map =  mapper.readValue(json, Map::class.java)

But now how to have the generic type definition?但是现在如何定义泛型类型呢?

Something like this does not compile:像这样的东西不能编译:

val map =  mapper.readValue(decodedString, Map<String, String>::class.java)

So my question is: What is the generic equivalent to *::class.java所以我的问题是: *::class.java的通用等价物是什么?

Class<T> (in Java) or KClass<T> (in Kotlin) can only represent classes , not all types. Class<T> (在 Java 中)或KClass<T> (在 Kotlin 中)只能表示classes ,而不是所有类型。 If the API you're using only uses Class<T> or KClass<T> , it simply doesn't support generic types (at least in those functions).如果您使用的 API 仅使用Class<T>KClass<T> ,它根本不支持泛型类型(至少在那些函数中)。

Instead, KType (or Type in Java) is the proper type to use to represent the complete type information including generics.相反, KType (或 Java 中的Type )是用于表示包括泛型在内的完整类型信息的正确类型。 You could use it this way:你可以这样使用它:

val myMapType: KType = typeOf<Map<String,String>>()

Unfortunately, KType doesn't have a type parameter (it's not KType<T> ), and that makes it impossible to use for compile-time type checking: you can't have the equivalent of fun deserialize(Input, KClass<T>): T using KType instead of KClass , because you can't define the T for the return type by using only a KType argument.不幸的是, KType没有类型参数(它不是KType<T> ),这使得它无法用于编译时类型检查:你不能拥有相当于fun deserialize(Input, KClass<T>): T使用KType而不是KClass ,因为您不能仅使用KType参数为返回类型定义T

There are several tricks to work around this:有几个技巧可以解决这个问题:

  • In both Java and Kotlin, one of the ways is to get this information through inheritance by providing a generic superclass and inheriting from it.在 Java 和 Kotlin 中,一种方法是通过提供泛型超类并从其继承来通过继承获取此信息。

    In general, serialization APIs (especially the deserializing part) provide workarounds using this, such as Jackson's TypeReference or Gson's TypeToken .一般来说,序列化 API(尤其是反序列化部分)提供了使用它的解决方法,例如 Jackson 的TypeReference或 Gson 的TypeToken It's basically their version of Type but with a type parameter to have some compile-time type safety.它基本上是他们的Type版本,但带有类型参数以具有一些编译时类型安全性。

  • In Kotlin, there is sometimes another way depending on the situation: making use of reified type parameters .在 Kotlin 中,有时根据情况还有另一种方法:使用具体类型参数 Using inline functions, the compiler can know more information at compile time about the type parameters by replacing them with the actual inferred type at the call site when inlining the function's body.使用内联函数,编译器可以在编译时了解更多关于类型参数的信息,方法是在内联函数体时将它们替换为调用站点的实际推断类型。 This allows things like T::class in the inline function's body.这允许像T::class这样的东西在内联函数的主体中。 This is how you can get functions like typeOf to get a KType .这就是你如何获得像typeOf这样的函数来获得KType的方法。

    Some Kotlin-specific APIs of deserialization libraries use inline functions to remove the hassle from the user, and get type information directly.一些 Kotlin 特定的反序列化库 API 使用内联函数来消除用户的麻烦,并直接获取类型信息。 This is what jackson-module-kotlin does by providing an inline readValue extension without a Class argument, which reifies the type parameter to get the target type information这就是jackson-module-kotlin通过提供不带Class参数的内联readValue扩展来实现的,它具体化类型参数以获取目标类型信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM