@foonfyrick

Как работает as? В чем отличие от преобразования типов?

Я никогда этим оператором не пользовался, но когда решил попробовать то, возникли некоторые трудности.
Я прочитал что это оператор приведения типа, то есть, если у меня есть 2 переменные разных примитивных типов, то я могу один сделать другим, то есть из long сделать int и т.д, но на деле я ловлю ошибку, прочитал в интернете, ничего не понял, и примеров не нашел. Можете привести пару примеров как им пользоваться?
Мне казалось что приведение типа и преобразование тоже самое, то есть:
var x = 'c'
var y = x.toInt()
или
var y = x as Int
  • Вопрос задан
  • 2071 просмотр
Решения вопроса 1
zagayevskiy
@zagayevskiy Куратор тега Kotlin
Android developer at Yandex
Нет, ты неправильно понял. as это про отношение родитель-потомок, которым упомянутые тобой Int, Long и Char не связаны. Поэтому ты получаешь ошибки. Что это значит: у тебя есть значение, имеющее тип "родитель"и ты хочешь привести его к типу "потомок".
Например:
fun f(n: Number): Int{
   return n as Int
}

f(10) // 10
f(10L) // ClassCastException

По второму примеру ты можешь понять, что делать приведение типов, если ты точно не знаешь, какой тип имеет инстанс, чревато ошибками в рантайме.
Поэтому есть форма as?, которая в случае неудачи возвращает null. А также есть оператор is, который проверяет, является ли объект инстансом определенного класса:
val x = 10
x is Int == true
x is Number == true
x is Any == true
x is Long == false
x as Int // redundent
val y: Long? = x as? Long //== null

Кроме того, в котлине есть такая прекрасная вещь, как смарткасты(умное приведение типов). Что это значит. Если компилятор видит, что ты проверил тип значения и это значение не может измениться, то он выводит соответвующий тип сам, и явный каст(as) не нужен. Это работает для условных выражений, if, when, elvis-operator, также если ты ранее делал каст.
val x: Any = ...
if (x is String) x.substring(0, 10)
if (x is Int) x + 10

x as Long // Long или ClassCastException
x + 10L // до этой точки выполнение дойдёт только в случае успешного каста.

И конечно это всё прекрасно работает с пользовательскими типами, божественно вместе с sealed классами:
sealed class B
class D1(val x: Int): B()
class D2(val y: String): B()
object D3: B()

fun f(b: B){
  when (b){
    is D1 -> b.x 
    is D2 -> b.y
    is D3 -> D3
  }
}

Это удобно для возвращения разных значений, обработки ошибок и тд.

Таким образом, использования as имеет смысл в довольно ограниченном числе случаев. Когда компилятор не может доказать что-то, но ты это точно знаешь. Например, в случае мутабельной проперти, или функции, возвращающей одно и то же значение.

Упомянутый тобой toInt это не преобразование типа, а обычная функция, которая возвращает новый тип по неким правилам.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
24 июл. 2024, в 05:17
50000 руб./за проект
24 июл. 2024, в 01:58
40000 руб./за проект
24 июл. 2024, в 01:55
5000 руб./за проект