Почему не может Kotlin неявно превратить Array of String в Array of Any? - PullRequest
0 голосов
/ 24 января 2020

Следующий код неявно переводит строку в Any.

    val s = "some string"
    val upcasted: Any = s

Однако следующее не компилируется (несоответствие типов):

    val s = arrayOf("some string")
    val upcasted: Array<Any> = s

Вы можете успешно привести к Array<Any> как показано:

    val s = arrayOf("some string")
    val upcasted: Array<Any> = s as Array<Any>

Однако это выдает предупреждение "Unchecked cast: Array<String> to Array<Any>". Тот же лог c , похоже, работает со списками, так что внутренняя реализация Array несовместима с этим типом приведения? Возможно, это из-за представления массивов в памяти?

1 Ответ

3 голосов
/ 24 января 2020

Вы не можете безопасно привести тип к супертипу или подтипу, как этот, потому что Array<String> не квалифицируется как Array<Any>. Если вы попытаетесь поместить Double в ваш предполагаемый Array<Any>, это вызовет исключение, потому что фактическим типом является массив String. Массивы являются особым случаем обобщений, которые не имеют стирания типов, поэтому они привязаны к типу, с которым они были созданы.

Что вы можете сделать, это привести его к Array<out Any>, потому что вы можете безопасно используйте это таким образом. Вы можете извлечь Strings из массива, и они будут считаться экземплярами Any. Обратное неверно. Вы не можете поместить любой экземпляр Any и его подклассов в массив String.

Когда дело доходит до List, вы можете привести его к списку с типом супертипа, и вам даже не нужно будет приводить его вручную. Это. Это безопасно, поэтому приведение может быть выполнено неявно.

val s = listOf("some string")
val upcasted: List<Any> = s // implicit cast

Так почему бы вам не выполнить приведение к List<out Any>? Интерфейс List не имеет каких-либо функций, позволяющих вам добавлять в него материал. Он определен с помощью out -проектированного типа в его объявлении, поэтому, когда вы набираете List<Any>, это уже то же самое, что и List<out Any>

Если вы попытаетесь сделать это с MutableList, который принимает в него элементы и не определен с out -проектированным типом, тогда вы столкнетесь с тем же предупреждением, что и с массивом.

val s = mutableListOf("some string")
val upcasted: MutableList<Any> = s as MutableList<Any> // warning here and implicit cast impossible

Разница между этим и массивом что есть стирание типа, поэтому у вас не будет исключения времени выполнения, если вы попытаетесь добавить не-String в этот список. Но есть вероятность скрытых ошибок, если вы не будете осторожны, поэтому предупреждение.

...