【问题标题】:Kotlin class literals with empty left hand side are not yet supported?尚不支持左侧为空的 Kotlin 类文字?
【发布时间】:2016-09-21 22:15:25
【问题描述】:

我正在尝试使用这样的 if 表达式检查一个类型是否符合另一种类型:

if (String::class is Any::class)

这给了我尚不支持左侧为空的错误类文字。谁能详细说明该错误和/或告诉我应该如何进行此检查?

编辑(澄清):我无法进行相等性检查,因为我需要知道左侧的类是否与右侧的类匹配或者是它的子类。因此,如果左侧类的实例可以安全地转换为右侧类。

基本上我需要相当于:

if ("A string" is Any)

但没有 String 实例,这里只是使用 String 的例子。

【问题讨论】:

标签: reflection kotlin type-safety


【解决方案1】:

我想如果 Kotlin 在 KClass 和另一个 KClass 之间使用 is 运算符的方式不同,就像在实例和类型之间那样,这就是为什么我试图做的事情没有不工作。不管怎样,我做了这个小中缀函数来模仿这个功能。但是它当然只适用于 JVM 目标,因为它使用 Java 反射。这与answer given in this SO post 不同。

infix fun <T : Any, C : Any> KClass<T>.can(comparate: KClass<C>) =
   comparate.java.isAssignableFrom(this.java)

这将允许您完全按照我的要求做,但使用 can 函数而不是像这样的 is 运算符:

if(String::class can Any::class)

【讨论】:

    【解决方案2】:

    您的错误消息是 is 检查需要一个类名,而不是对右侧 KClass 的引用。消息本身可能有点不清楚。但同样适用于 Java,您不会使用 instanceOf 运算符,而是调用 isAssignableFrom

    有关解决问题的帮助,您可以在 Github 中找到示例...

    Klutter library 中是ClassKClassTypeKType 之间的许多instanceOf 样式检查组合的示例以及原语。你可以从那里复制想法。从长远来看,您可能希望涵盖许多组合。

    这里是a big mix of extensions 的示例,用于检查一种类型是否可以从另一种分配。举几个例子:

    fun <T : Any, O : Any> KClass<T>.isAssignableFrom(other: KClass<O>): Boolean {
        if (this.java == other.java) return true
        return this.java.isAssignableFrom(other.java)
    }
    
    fun <T : Any> KClass<T>.isAssignableFrom(other: Class<*>): Boolean {
        if (this.java == other) return true
        return this.java.isAssignableFrom(other)
    }
    
    fun KClass<*>.isAssignableFromOrSamePrimitive(other: KType): Boolean {
        return (this.java as Type).isAssignableFromOrSamePrimitive(other.javaType) 
    }
    
    fun KClass<*>.isAssignableFromOrSamePrimitive(other: Type): Boolean {
        return (this.java as Type).isAssignableFromOrSamePrimitive(other)
    }
    
    fun Type.isAssignableFromOrSamePrimitive(other: Type): Boolean {
        if (this == other) return true
        if (this is Class<*>) {
            if (other is Class<*>) {
                return this == other.kotlin.javaObjectType || this == other.kotlin.javaPrimitiveType ||
                        this.isAssignableFrom(other)
            }
            return this.isAssignableFrom(other.erasedType())
        }
        return this.erasedType().isAssignableFrom(other.erasedType())
    }
    
    // ... and so on for every permutation of types
    

    请参阅linked source for all permutations

    您将需要上述示例使用的erasedType() extension——它从Type 回到Class(在类型擦除之后):

    @Suppress("UNCHECKED_CAST") fun Type.erasedType(): Class<Any> {
        return when (this) {
            is Class<*> -> this as Class<Any>
            is ParameterizedType -> this.getRawType().erasedType()
            is GenericArrayType -> {
                // getting the array type is a bit trickier
                val elementType = this.getGenericComponentType().erasedType()
                val testArray = java.lang.reflect.Array.newInstance(elementType, 0)
                testArray.javaClass
            }
            is TypeVariable<*> -> {
                // not sure yet
                throw IllegalStateException("Not sure what to do here yet")
            }
            is WildcardType -> {
                this.getUpperBounds()[0].erasedType()
            }
            else -> throw IllegalStateException("Should not get here.")
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-23
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      相关资源
      最近更新 更多