Operator as w Kotlinie jest używany do jawnego rzutowania typów (cast). Istnieją dwa warianty: as i as?. Pierwszy wyrzuca wyjątek, drugi — jest bezpieczniejszy. To narzędzie jest ważne w pracy z polimorfizmem, a także w migracji danych i interakcji z zewnętrznymi API.
W Javie przy rzutowaniu typów używany jest operator-cast (TargetType)obj, który pada z ClassCastException przy błędzie. Kotlin rozwinął tę koncepcję, dodając bezpieczny cast (as?), co pozwoliło na wygodne i explicite zarządzanie nullability i błędami czasu wykonania.
Sztywne rzutowanie typów w dużym projekcie jest niebezpieczne: jeśli typ się nie zgadza, program po prostu się zawiesza (ClassCastException). Należy minimalizować takie zachowanie bez Silent-error'ów czy NPE. Ważne jest, aby dobrze rozdzielać sytuacje, gdy błąd powinien być obsłużony, a kiedy można po prostu zwrócić null.
Kotlin dostarcza dwa operatory:
as: sztywne rzutowanie typu, przy niezgodności typów wyrzuca ClassCastException.as?: bezpieczne rzutowanie — zwraca null, jeśli cast jest niemożliwy.val x: Any = "Hello, Kotlin!" val s1: String = x as String // Ok, x to String val s2: String? = x as? String // Ok, x to String val n: Int? = x as? Int // n = null, bezpieczny cast
as wyrzuca ClassCastException przy błędzie.as? zwraca null, minimalizując awaryjne błędy.Czy 'as' zawsze sprawdza typ w czasie wykonania?
Tak, jeśli cast odbywa się z niekompatybilnymi typami, powstanie ClassCastException. Jednak dla niektórych nie-jawnych konwersji, na przykład, między Int a Float, takie rzutowanie nie ma miejsca — idiomatyczna konwersja w Kotlinie odbywa się przez metody (toInt, toFloat).
Czy można używać 'as' z nullable-typu na not-null-typ?
Tak, ale bądź ostrożny: jeśli wartość okaże się null, zostanie wyrzucony wyjątek. Jakiekolwiek cast nullable-typu do nie-nullable bez sprawdzenia może prowadzić do błędu w czasie wykonania.
val x: String? = null val y: String = x as String // wyrzuci ClassCastException!
Jaka jest różnica między 'is' a 'as'?
'is' — to operator sprawdzania typu. Zwraca true/false, nie rzutuje typu. 'as' faktycznie rzutuje typ, a jeśli to niemożliwe, wyrzuca wyjątek (lub zwraca null przy użyciu 'as?'). Często są używane razem do bezpiecznego rzutowania:
if (x is String) { val s: String = x // smart cast }
as bez sprawdzania typu, co prowadzi do ClassCastException.W module parsowania danych wszystkie obiekty są parsowane przez as, na przykład, obj as Double. Jeśli dane są błędne — aplikacja pada z ClassCastException.
Plusy:
Minusy:
Zastosowanie konstrukcji smart-cast (przez is) lub bezpiecznego castu (as?):
val price = (obj as? Double) ?: 0.0
Plusy:
Minusy: