尚未支持空左侧的Kotlin类文字?

时间:2016-09-21 22:15:25

标签: reflection kotlin type-safety

我试图检查一个类型是否符合if表达式的另一个类型:

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

这使我不支持具有空左侧的错误类文字。任何人都可以详细说明这个错误和/或告诉我应该怎么做这个检查吗?

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

基本上我需要相当于:

if ("A string" is Any)

但是没有String实例,String只是在这里使用了一个例子。

2 个答案:

答案 0 :(得分:4)

我想不清楚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)

答案 1 :(得分:3)

您的错误消息是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.")
    }
}