Smart casting to mechanizm, w którym kompilator Kotlin automatycznie "obniża" typ po sprawdzeniu na określony typ lub null. Pozwala to na używanie właściwości i metod tego typu, na który dokonano rzutowania, bez jawnej konwersji.
fun demo(x: Any) { if (x is String) { println(x.length) // x automatycznie rzucony do String } }
Działa z:
is / !is (np. w if lub when)if (x != null))whenNie działa:
val str: String? = getString() if (str != null) println(str.length) // smart cast
val something: Any get() = fetch() if (something is String) { println(something.length) // Błąd: smart cast niemożliwe }
Czy można liczyć na smart cast dla właściwości open lub var klasy wewnątrz metod?
Nie! Smart cast działa tylko z lokalnymi zmiennymi i właściwościami val w klasach finalnych. Dla otwartych (open) lub właściwości var, kompilator nie jest pewny, czy wartość może zostać zmieniona przez inne wątki lub podklasy. Wymagana jest ręczna konwersja lub lokalna zmienna.
open class Base { open var maybeString: Any? = "abc" fun check() { if (maybeString is String) { // println(maybeString.length) // Błąd: smart cast niemożliwe val asString = maybeString as String println(asString.length) // Jawna konwersja } } }
Historia
W jednym projekcie do logiki ekranów używano otwartych właściwości var modelu danych. Programista polegał na smart cast po sprawdzeniu if (model is SomeType), jednak podczas kompilacji musiał wszystko ręcznie konwertować, co pogorszyło czytelność i dodało duplikację kodu z powodu nieznajomości ograniczenia smart cast na var/open.
Historia
Podczas pobierania danych przez getter (np. przez delegację lub walidację), smart cast dla wartości nie zadziałał. Programista nie zrozumiał przyczyn i spędził kilka godzin na debugowaniu, aż odkrył, że kompilator nie stosuje smart cast do takich getterów, ponieważ mogą one zwracać różne wartości między wywołaniami.
Historia
W projekcie podczas przetwarzania wartości nullable przez if (obj != null) smart cast działał wewnątrz gałęzi, a podczas równoległego przetwarzania kodu pojawiły się NullPointerException z powodu odwołań poza obszarem gwarancji. Pokazało to niewystarczające rozumienie lokalnego działania smart cast oraz istotnych cech wielowątkowych scenariuszy pracy z zmiennymi nullable.