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

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

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

但编译器抱怨

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

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

if (value is String) { ... }

使用了 Kotlin 0.4.68。

我在这里错过了什么?

【问题讨论】:

    标签: generic-programming kotlin


    【解决方案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?>?) {
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 2010-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-10
        相关资源
        最近更新 更多