Kotlin: возвращение Array <E>из функции с типом возврата Array <I>, если E является классом enum, который реализует интерфейс I - PullRequest
0 голосов
/ 15 января 2019

Недавно я столкнулся с проблемой, когда у меня была функция, которая должна была возвращать массив I с в виде всех значений enum E, с E реализующим интерфейс I, с каждым кодом пришедший мне в голову компилятор пожаловался на несоответствие типов:

Error:(x, x) Kotlin: Type mismatch: inferred type is Array<E> but Array<I> was expected

Минимальный пример:

    interface I {}
    enum class E: I {
        A, B, C;
    }
    fun getMoreInterfaces(): Array<I> {
        return E.values()
    }

Это происходит при попытке присвоить E.values() переменной типа Array<I> Я уверен, что это должно быть возможно, поскольку E реализует I.

Еще одна вещь, которую я обнаружил во время тестирования, это то, что она работает просто отлично, когда используется так:

    interface I {}
    enum class E: I {
        A, B, C;
    }
    fun getMoreInterfaces(): Array<I> {
        return arrayOf(E.A, E.B, E.C)
    }

Я много искал по этой теме, но безуспешно (возможно, я выбрал неправильный способ описать это?)

Ответы [ 2 ]

0 голосов
/ 12 июля 2019

Array - это инвариантный универсальный тип в Kotlin, поэтому, если вам нужно вернуть экземпляр Array<I>, вы не можете вместо него вернуть Array<E>, даже если E является подтипом I.

Но если вы только потребляете значений из возвращенного массива, вы можете объявить его тип как Array<out I>. Этот тип является ковариантной проекцией типа Array<I> и позволяет возвращать Array<I> и Array<E>.

interface I {}
enum class E: I {
    A, B, C
}
fun getMoreInterfaces(): Array<out I> {
    return E.values()
}
0 голосов
/ 15 января 2019

В Kotlin, в отличие от Java, Array<T> является инвариантом для T, поэтому для E, который является подтипом I, Array<E> и Array<I>, не являются подтипами друг друга. См .: Дисперсия .

Учитывая, что типы Array<T> также хранят тип элемента и не могут быть полностью непроверенными приведениями , лучший способ решить эту проблему - создать отдельный массив.

Вы можете сделать это либо путем создания массива вручную и заполнения его элементами, как в вашем примере (или с помощью конструктора Array(n) { ... }), либо с помощью .toTypedArray() применяется к представлению списка массива (.asList()):

fun getMoreInterfaces(): Array<I> {
    return E.values().asList().toTypedArray()
}

(готовый образец)

Но, в принципе, вы можете просто пойти с List<I>, если вы не в критически важном для кода коде, что для Kotlin идиоматичнее, чем работа с массивами, а также проще.

См. Также: Разница между типами List и Array в Kotlin

...