在Kotlin中推断Map的通用类型 [英] Inferring a generic type of Map in Kotlin

查看:583
本文介绍了在Kotlin中推断Map的通用类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一个Java方法,该方法通过Java类来推断其类型,如下所示:

Consider a Java method which infers its type by Java class as follows:

public <T> T readJson(Class<T> c) throws IOException {

这允许执行以下操作:

Map<String, String> map = foo.readJson(Map.class);

在Java中,它将警告未检查的强制转换,但可以正常工作.但是在Kotlin中,这并不是那么容易,可以尝试使用:

In java it will warn about unchecked cast, but it will work correctly. However in Kotlin, this will not be so easy, one could try using:

foo.readJson(Map::class.java)

但是,如果需要Map<String, String>,它将不起作用:

However if Map<String, String> will be required, it will not work:

Type inference failed. Expected type mismatch.
required Map<String, String>
found Map<*, *>!

我也尝试定义一个接口StringMap:

I also tried defining an interface StringMap:

interface StringMap : Map<String, String>

但是无论如何也不起作用,它会导致如下异常:

However that does not work either, it will lead to exceptions like this:

Cannot cast ...LinkedTreeMap to ...StringMap

这样做的正确方法是什么?

What would be a correct way of doing this?

推荐答案

Kotlin没有类似Java原始类型(为了向后兼容而保留在Java中)的类型,因此类型系统不允许这种未经检查的赋值隐式制作(星空投影,最接近的概念到Kotlin中的原始类型,请保留类型安全性.

Kotlin does not have anything like Java raw types (which were left in Java for backward compatibility), and the type system therefore does not allow this kind of unchecked assignment to be made implicitly (star projections, the closest concept to raw types in Kotlin, retain type safety).

您可以不加限制地强制转换为Map<String, String>,从而表示您知道运行时类型可能不匹配:

You can make an unchecked cast to Map<String, String>, thus expressing that you are aware of a possible type mismatch at runtime:

@Suppress("UNCHECKED_CAST")
val result = foo.readJson(Map::class.java) as Map<String, String>

您可以抑制未经检查的强制转换警告范围比仅仅一个语句还宽.

You can suppress the unchecked cast warning for a broader scope than just one statement.

此解决方案的自然改进是编写一个util函数,以在其中隐藏未经检查的演员表:

A natural improvement of this solution is writing a util function to hide the unchecked cast in it:

@Suppress("UNCHECKED_CAST")
inline fun <reified T: Any> JsonReader.readJson(): T {
    val result = readJson(T::class.java)
    return result as T
}

此解决方案使用带有经过修饰的内联函数类型参数:函数在其每个调用位置进行转换和替换,在编译时将T替换为指定的(或推断的)类型.

This solution uses an inline function with a reified type parameter: the function is transformed and substituted at each of its call sites, with T replaced by the specified (or inferred) type at compile time .

用法示例:

val map = jsonReader.readJson<Map<String, String>>()

fun processMap(map: Map<String, String) { /* ... */ }

processMap(jsonReader.readJson()) // Map<String, String> is inferred for this call

这篇关于在Kotlin中推断Map的通用类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆