Kotlin cast any to map

Приведение и проверка типов

Используйте оператор is или его отрицание !is , чтобы проверить соответствует ли объект заданному типу во время исполнения.

if (obj is String) < print(obj.length) >if (obj !is String) < // то же самое, что и !(obj is String) print("Not a String") >else

Умные приведения

В большинстве случаев вам не нужно использовать явные приведения в Kotlin, потому что компилятор отслеживает is -проверки и явные преобразования для неизменяемых значений и вставляет (безопасно) приведения автоматически, там, где они нужны.

Компилятор достаточно умён для того, чтобы понимать, что приведения безопасны в случаях, когда проверка на несоответствие типу ( !is ) приводит к выходу из функции:

if (x !is String) return print(x.length) // x автоматически преобразовывается в String 

или в случаях, когда приводимая переменная находится справа от оператора && или || , а соответствующая проверка (обычная или отрицательная) находится слева:

// x автоматически преобразовывается в String справа от `||` if (x !is String || x.length == 0) return // x автоматически преобразовывается в String справа от `&&` if (x is String && x.length > 0) < print(x.length) // x автоматически преобразовывается в String >

Умные приведения работают вместе с when -выражениями и циклами while :

when (x) < is Int ->print(x + 1) is String -> print(x.length + 1) is IntArray -> print(x.sum()) > 

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

  • с локальными val переменными — всегда за исключением локальных делегированных свойств.;
  • с val свойствами — если поле имеет модификатор доступа private или internal , или проверка происходит в том же модуле, в котором объявлено это свойство. Умные приведения неприменимы к публичным свойствам или свойствам, которые имеют переопределённые getter’ы;
  • с локальными var переменными — если переменная не изменяется между проверкой и использованием, не захватывается лямбдой, которая её модифицирует и не является локальным делегированным свойством;
  • с var свойствами — никогда, потому что переменная может быть изменена в любое время другим кодом.

Оператор «небезопасного» приведения

Обычно оператор приведения выбрасывает исключение, если приведение невозможно, поэтому мы называем его небезопасным. Небезопасное приведение в Kotlin выполняется с помощью инфиксного оператора as :

val x: String = y as String 

Заметьте, что null не может быть приведен к String , так как String не является nullable, т.е. если y — null, код выше выбросит исключение. Чтобы сделать этот код корректным для null-значений, используйте nullable-тип в правой части приведения.

val x: String? = y as String? 

Оператор «безопасного» (nullable) приведения

Чтобы избежать исключения, вы можете использовать оператор безопасного приведения as? , который возвращает null в случае неудачи.

val x: String? = y as? String 

Заметьте, что несмотря на то, что справа от as? стоит non-null тип String , результат приведения является nullable.

Читайте также:  Access connector java jar

Стирание и проверка типов у Обобщений (Generics)

` is erased to just `List `. In general, there is no way to check whether an instance belongs to a generic type with certain type arguments at runtime. —>

Котлин обеспечивает типобезопасность операций, связанных с обобщениями на этапе компиляции, в то время как информация о типе аргумента обобщения недоступна во время выполнения программы. Например, для List происходит стирание типа, что превращает его в List . В связи с чем, нет способа проверить, принадлежит ли объект конкретному типу во время выполнения программы.

` or `list is T` (type parameter). You can, however, check an instance against a [star-projected type](generics.md#star-projections): —>

Учитывая это, компилятор запрещает is -проверки, которые не могут быть выполнены во время выполнения программы из-за стирания типов, например ints is List или list is T (параметризированный тип). Однако у вас есть возможность произвести проверку со «звёздными» проекциями.

if (something is List) < something.forEach < println(it) >// Элементы типа `Any?` > 

Таким же образом, когда у вас есть статически определенный тип аргумента, вы можете произвести is -проверку или приведение с необобщенной частью типа. Заметьте, что в данном случае угловые скобки пропущены:

fun handleStrings(list: List) < if (list is ArrayList) < // `list` приводится к `ArrayList` путём "умного приведения" > > 

Аналогичный синтаксис, но с пропущенным типом аргумента может использоваться для приведений, которые не принимают типы аргументы: list as ArrayList .

Встроенные (inline) функции с параметрами вещественного типа имеют свои аргументы типа, встроенные на каждый момент вызова, что позволяет arg is T проверять параметризованный тип, но если arg является объектом обобщенного типа, его аргумент типа по-прежнему стираются.

inline fun Pair.asPairOf(): Pair? < if (first !is A || second !is B) return null return first as A to second as B >val somePair: Pair = "items" to listOf(1, 2, 3) val stringToSomething = somePair.asPairOf() val stringToInt = somePair.asPairOf() val stringToList = somePair.asPairOf>() val stringToStringList = somePair.asPairOf>() // Нарушает типобезопасность! fun main()

Непроверяемые (Unchecked) приведения

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

Тем не менее иногда мы имеем программную логику высокого уровня, которая подразумевает типобезопасность.

fun readDictionary(file: File): Map = file.inputStream().use < TODO("Прочитать сопоставление строк с произвольными элементами.") >// Мы сохранили словарь (map) `Int`ов в файл val intsFile = File("ints.dictionary") // Warning: Unchecked cast: `Map` to `Map` val intsDictionary: Map = readDictionary(intsFile) as Map

Компилятор выдает предупреждение для приведения в последней строке. Приведение не может быть полностью проверено во время выполнения и нет дает гарантии, что значения в словаре (map) являются Int .

` and `DictionaryWriter ` interfaces with type-safe implementations for different types. You can introduce reasonable abstractions to move unchecked casts from the call site to the implementation details. Proper use of [generic variance](generics.md#variance) can also help. -->

Чтобы избежать непроверяемые приведения, вы можете изменить структуру программы: в примере выше возможно объявить интерфейсы DictionaryReader и DictionaryWriter с типобезопасными имплементациями для различных типов. Правильное использование вариативности обобщений также может помочь.

Для обобщенных функций, используемых встроенные (inline) функции с параметрами вещественного типа приведение типа arg as T является проверяемым, до тех пор, пока тип arg не имеет свои аргументы типа, которые были стерты.

Предупреждение о непроверяемом приведении можно убрать используя аннотации @Suppress("UNCHECKED_CAST") .

inline fun List.asListOfType(): List? = if (all < it is T >) @Suppress("UNCHECKED_CAST") this as List else null 

В JVM, массивы ( Array ) сохраняют информацию о стираемом типе их элементов, и приведение типов к массиву частично проверяется: nullability и фактические аргументы для параметризированных элементов массива все еще стираются. Например, приведение foo as Array ?> будет успешным, если foo является массивом List , независимо от того, является ли он nullable или нет.

© 2015—2023 Open Source Community

Источник

Kotlin Cast Any to List or Map: Unchecked Cast

When casting Any? to List , there is a warning of Unchecked Cast: Any? to List .

// items is Any?val ids = items as ListString>

If you trust the source to contain the appropriate type, you use

@Suppress("UNCHECKED_CAST")val ids = items as? ListString>

For UNCHECKED_CAST in object constructor or function parameters.

@Suppress("UNCHECKED_CAST")val item = Quote( mainTags = mainTags as? ListString> )

If you don't trust the source and want to do runtime checking and verification

val ids = items as? List if (ids != null)  for (id in ids.filterIsInstanceString>())  // do something >>

NOTE: filterIsInstance only return elements which match the type (and remove those who doesn't)

val ids = items as? List for (id in ids)  if (id is String)  // do something >>

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.

Источник

Type checks and casts

Use the is operator or its negated form !is to perform a runtime check that identifies whether an object conforms to a given type:

Smart casts

In most cases, you don't need to use explicit cast operators in Kotlin because the compiler tracks the is -checks and explicit casts for immutable values and inserts (safe) casts automatically when necessary:

The compiler is smart enough to know that a cast is safe if a negative check leads to a return:

or if it is on the right-hand side of && or || and the proper check (regular or negative) is on the left-hand side:

// x is automatically cast to String on the right-hand side of `||` if (x !is String || x.length == 0) return // x is automatically cast to String on the right-hand side of `&&` if (x is String && x.length > 0) < print(x.length) // x is automatically cast to String >

Smart casts work for when expressions and while loops as well:

Note that smart casts work only when the compiler can guarantee that the variable won't change between the check and the usage. More specifically, smart casts can be used under the following conditions:

  • val local variables - always, with the exception of local delegated properties.
  • val properties - if the property is private or internal or if the check is performed in the same module where the property is declared. Smart casts cannot be used on open properties or properties that have custom getters.
  • var local variables - if the variable is not modified between the check and the usage, is not captured in a lambda that modifies it, and is not a local delegated property.
  • var properties - never, because the variable can be modified at any time by other code.

"Unsafe" cast operator

Usually, the cast operator throws an exception if the cast isn't possible. And so, it's called unsafe. The unsafe cast in Kotlin is done by the infix operator as .

Note that null cannot be cast to String , as this type is not nullable. If y is null, the code above throws an exception. To make code like this correct for null values, use the nullable type on the right-hand side of the cast:

"Safe" (nullable) cast operator

To avoid exceptions, use the safe cast operator as? , which returns null on failure.

Note that despite the fact that the right-hand side of as? is a non-null type String , the result of the cast is nullable.

Generics type checks and casts

Please see the corresponding section in the generics documentation page for information on which type checks and casts you can perform with generics.

Источник

Оцените статью