如何在 Kotlin 中检查泛型类型

Posted

技术标签:

【中文标题】如何在 Kotlin 中检查泛型类型【英文标题】:How can I check for generic type in Kotlin 【发布时间】:2012-10-31 09:07:47 【问题描述】:

我正在尝试在 Kotlin 中测试泛型类型。

if (value is Map<String, Any>)  ... 

但编译器抱怨

无法检查擦除类型的实例:jet.Map

普通类型的检查效果很好。

if (value is String)  ... 

使用了 Kotlin 0.4.68。

我在这里错过了什么?

【问题讨论】:

【参考方案1】:

问题是类型参数被删除了,所以你不能检查完整的类型 Map,因为在运行时没有关于这些 String 和 Any 的信息。

要解决此问题,请使用通配符:

if (value is Map<*, *>) ...

【讨论】:

太棒了!这完全有效!我只是对文档中的示例感到困惑:confluence.jetbrains.net/display/Kotlin/Type+casts 如果您真的想检查某个东西是否是 Collection&lt;String&gt; 以使其自动投射,该怎么办? 我有这样的sn-p if (it.getSerializable(ARG_PARAMS) is HashMap&lt;*, *&gt;) it.getSerializable(ARG_PARAMS) as HashMap&lt;String, String&gt; else null。所以基本上如果我检查泛型类型,它会尝试将HashMap&lt;String, Integer&gt; 转换为HashMap&lt;String, String&gt;。我错过了什么吗? @FARID 是的,会的,而且这种演员阵容不安全【参考方案2】:

我觉得这样比较合适

inline fun <reified T> tryCast(instance: Any?, block: T.() -> Unit) 
    if (instance is T) 
        block(instance)
    

用法

// myVar is nullable
tryCast<MyType>(myVar) 
    // todo with this e.g.
    this.canDoSomething()

另一种更短的方法

inline fun <reified T> Any?.tryCast(block: T.() -> Unit) 
    if (this is T) 
        block()
    

用法

// myVar is nullable
myVar.tryCast<MyType> 
    // todo with this e.g.
    this.canDoSomething()

【讨论】:

为什么这样的东西不能直接在 kotlin stdlib 中使用:-( something as? String不一样吗?注意as之后的问号? @DaliborFilus 不。这是关于运行时的泛型和擦除类型。如果你不需要处理泛型,你可以使用as?,对。【参考方案3】:

JVM 删除了泛型类型信息。但是 Kotlin 已经具体化了泛型。如果你有一个泛型类型 T,你可以将内联函数的类型参数 T 标记为 reified,以便它能够在运行时检查它。

所以你可以这样做:

inline fun <reified T> checkType(obj: Object, contract: T) 
  if (obj is T) 
    // object implements the contract type T
  

【讨论】:

你能举例说明如何调用checkType()吗?我不确定第二个参数应该传递什么。 @MichaelOsofsky checkType(myMapOfStrings, Map&lt;String, Any&gt;)【参考方案4】:

我会给出一个变通的解决方案,但我认为它很干净,有点

try
  (value as Map<String,Any>?)?.let  castedValue ->
     doYourStuffHere() //using castedValue
  
catch(e: Exception)
  valueIsNotOfType() //Map<String,Any>

【讨论】:

【参考方案5】:

我已经用tryCast&lt;Array&lt;String?&gt;&gt; 尝试了上面的解决方案,我想,在我列出涉及许多铸件的具体任务中,这并不是一个好主意,因为它大大降低了性能。

这是我最后做的解决方案——手动检查条目和调用方法,像这样:

 fun foo() 
    val map: Map<String?, Any?> = mapOf()
    map.forEach  entry ->
        when (entry.value) 
            is String -> 
                doSomeWork(entry.key, entry.value as String)
            
            is Array<*> -> 
                doSomeWork(entry.key, (entry.value as? Array<*>)?.map 
                    if (it is String) 
                        it
                     else null
                ?.toList())
            
        
    



private fun doSomeWork(key: String?, value: String) 


private fun doSomeWork(key: String?, values: List<String?>?) 


【讨论】:

以上是关于如何在 Kotlin 中检查泛型类型的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Kotlin 中检查泛型类型

Kotlin 泛型中的 in 和 out

Java 泛型泛型用法 ( 泛型类用法 | 泛型方法用法 | 泛型通配符 ? | 泛型安全检查 )

java 方法中如何在返回类型使用泛型

java中如何得到泛型参数的class?

Kotlin 泛型