@foonfyrick

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

Я никогда этим оператором не пользовался, но когда решил попробовать то, возникли некоторые трудности.
Я прочитал что это оператор приведения типа, то есть, если у меня есть 2 переменные разных примитивных типов, то я могу один сделать другим, то есть из long сделать int и т.д, но на деле я ловлю ошибку, прочитал в интернете, ничего не понял, и примеров не нашел. Можете привести пару примеров как им пользоваться?
Мне казалось что приведение типа и преобразование тоже самое, то есть:
var x = 'c'
var y = x.toInt()
или
var y = x as Int
  • Вопрос задан
  • 2237 просмотров
Решения вопроса 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 это не преобразование типа, а обычная функция, которая возвращает новый тип по неким правилам.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы