Литералы класса Kotlin с пустой левой стороной еще не поддерживаются?

Я пытаюсь проверить, соответствует ли тип другому типу с таким выражением if:

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

Это дает мне литералы классов ошибок с пустой левой стороной, которые еще не поддерживаются. Может ли кто-нибудь уточнить эту ошибку и / или сказать мне, как мне делать эту проверку?

изменить (пояснение): я не могу выполнить проверку на равенство, потому что мне нужно знать, соответствует ли класс слева классу справа или является его подклассом. Итак, если экземпляр класса слева можно безопасно преобразовать в класс справа.

В основном мне нужен эквивалент:

if ("A string" is Any)

Но без экземпляра String, String здесь просто используется в качестве примера.


person zjuhasz    schedule 21.09.2016    source источник
comment
Мой коллега нашел еще одно сообщение SO, в котором говорится, что у Kotlin нет возможности сделать это, и единственный способ - использовать отражение Java (при условии, что вы нацеливаетесь на JVM). stackoverflow.com/questions/ 35851719 /   -  person zjuhasz    schedule 22.09.2016


Ответы (2)


Ваше сообщение об ошибке заключается в том, что проверка is ожидает имя класса, а не ссылку на KClass с правой стороны. Само сообщение может быть немного неясным. Но то же самое применимо и в Java: вы не будете использовать оператор instanceOf, а вместо этого вызовете isAssignableFrom.

Чтобы помочь в решении проблемы, у вас есть примеры, которые можно найти в Github ...

В библиотеке Klutter приведены примеры множества комбинаций проверки стиля instanceOf между Class, KClass, Type и KType а также примитивы. Вы можете копировать идеи оттуда. Есть много комбинаций, которые вы, возможно, захотите использовать в долгосрочной перспективе.

Вот пример большой набор расширений для проверки, можно ли назначить один тип другому. Вот несколько примеров:

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

См. связанный источник для все перестановки.

И вам понадобится этот _ 9_ расширение, используемое в приведенных выше примерах, которое изменяется от 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.")
    }
}
person Jayson Minard    schedule 21.09.2016

Думаю, было бы непонятно, использовал ли Kotlin оператор is по-разному между KClass и другим KClass, как между экземпляром и типом, поэтому то, что я пытался сделать, не работает. В любом случае я сделал эту маленькую инфиксную функцию, чтобы имитировать ее функциональность. Однако, конечно, он работает только с целью JVM, поскольку использует отражение Java. Это выходит из ответа, данного в этом сообщении SO .

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)
person zjuhasz    schedule 21.09.2016