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

Ответ

Приведение типов (type casting) — это преобразование значения одного типа в другой. В Kotlin/Java есть два вида:

  1. Явное приведение (explicit) — требует указания типа:
val num: Int = 42
val longNum: Long = num.toLong() // явное
  1. Неявное приведение (implicit) — автоматическое, когда компилятор уверен в безопасности:
val longNum: Long = 42L
val doubleNum: Double = longNum.toDouble()

Важно:

  • В Kotlin нет автоматического приведения для чисел (в отличие от Java)
  • Для классов используется оператор as (опасный) или as? (безопасный):
val obj: Any = "String"
val str: String = obj as String // может выбросить ClassCastException

Smart casts работают, когда компилятор может доказать тип:

if (obj is String) {
    println(obj.length) // автоматическое приведение
}

Ответ 18+ 🔞

А, ну это про то, как одно в другое превращать, да? Типа, был у тебя целый бутерброд, а ты его в крошки покрошил — вроде то же самое, но уже не намажешь. Так вот, в Котлине с этим строго, не как в той старой Java, где всё само текло куда попало.

Смотри, есть два подхода, как бабка на базаре: либо ты прямо говоришь, что тебе надо, либо надеешься, что тебя поймут правильно.

Первый — явный, когда ты сам всё контролируешь. Ты прямо командуешь: «Эй, число, стань длинным!». И пишешь это в коде.

val num: Int = 42
val longNum: Long = num.toLong() // вот, явно сказал — toLong!

Второй — неявный, когда компилятор такой умный и сам догадывается. Но, блядь, в Котлине с числами он на такое почти не способен! Не то что в Джяве, где int в long сам залезет. Тут надо явно просить. Хотя для некоторых простых случаев работает:

val longNum: Long = 42L
val doubleNum: Double = longNum.toDouble() // опять toDouble, ёпта!

А теперь самое интересное — с объектами. Вот тут начинается цирк. Есть оператор as — это как прыжок с парашютом без проверки строп. Может, полетишь, а может, пиздец.

val obj: Any = "String"
val str: String = obj as String // Всё ок, obj — строка. Но если бы там было число — ClassCastException, и привет, программа накрылась медным тазом.

Поэтому умные люди используют безопасный as?, который в случае провала просто вернёт null. Не летит в пропасть, а аккуратно говорит: «Не, чувак, не вышло».

val notAString: Any = 12345
val str: String? = notAString as? String // str будет null, а не краш. Уже лучше.

Но есть же и магия — умные приведения (smart casts). Это когда компилятор, видя твою проверку, сам всё понимает. Красота, ядрёна вошь!

if (obj is String) {
    println(obj.length) // Внутри этого if компилятор УЖЕ ЗНАЕТ, что obj — String. Можно сразу length вызывать, без всяких 'as'. Сам додумался!
}

Вот и вся философия. Не надеяться на авось, а явно указывать, что во что превращать. А компилятор, если видит, что ты уже проверил, — поможет и сделает всё сам. Главное — не пытаться запихнуть Int в String через as, а то будет тебе хиросима, а не программа.