考虑一个Java方法,它通过Java类推断出它的类型,如下所示:
public <T> T readJson(Class<T> c) throws IOException {
Run Code Online (Sandbox Code Playgroud)
这允许做这样的事情:
Map<String, String> map = foo.readJson(Map.class);
Run Code Online (Sandbox Code Playgroud)
在java中它将警告未经检查的强制转换,但它将正常工作.但是在Kotlin中,这不会那么容易,可以尝试使用:
foo.readJson(Map::class.java)
Run Code Online (Sandbox Code Playgroud)
但是,如果Map<String, String>
需要,它将无法工作:
Type inference failed. Expected type mismatch.
required Map<String, String>
found Map<*, *>!
Run Code Online (Sandbox Code Playgroud)
我还尝试定义一个接口StringMap:
interface StringMap : Map<String, String>
Run Code Online (Sandbox Code Playgroud)
然而,这也不起作用,它将导致这样的例外:
Cannot cast ...LinkedTreeMap to ...StringMap
Run Code Online (Sandbox Code Playgroud)
这样做的正确方法是什么?
hot*_*key 11
Kotlin没有像Java原始类型那样的东西(为了向后兼容而留在Java中),因此类型系统不允许隐式地进行这种未经检查的赋值(星形投影,与Kotlin中原始类型最接近的概念,保持类型安全).
您可以进行未经检查的强制转换Map<String, String>
,从而表示您在运行时意识到可能的类型不匹配:
@Suppress("UNCHECKED_CAST")
val result = foo.readJson(Map::class.java) as Map<String, String>
Run Code Online (Sandbox Code Playgroud)
您可以禁止未检查的强制转换警告,而不仅仅是一个语句.
这个解决方案的一个自然改进是编写一个util函数来隐藏其中未经检查的强制转换:
@Suppress("UNCHECKED_CAST")
inline fun <reified T: Any> JsonReader.readJson(): T {
val result = readJson(T::class.java)
return result as T
}
Run Code Online (Sandbox Code Playgroud)
此解决方案使用带有reified类型参数的内联函数:函数在其每个调用站点进行转换和替换,并T
在编译时由指定(或推断)类型替换.
用法示例:
val map = jsonReader.readJson<Map<String, String>>()
Run Code Online (Sandbox Code Playgroud)
fun processMap(map: Map<String, String) { /* ... */ }
processMap(jsonReader.readJson()) // Map<String, String> is inferred for this call
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3266 次 |
最近记录: |