Smartcast es imposible porque propery tiene getter abierto o personalizado

Estoy aprendiendo Kotlin. Mi código es el siguiente:

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) decoupler.attachNotifier(this) if(activity is ScreenRouter) { decoupler.attachRouter(activity) } } 

attachRouter() :

  fun attachRouter(router: ScreenRouter?) { this.router = router } 

Como se escribe en la documentación , kotlin automáticamente lanza al tipo después de comprobar con es operador. Por lo tanto, esperaba que funcionara. Pero en lugar de eso me molesta con el error de compilación diciendo:

Smartcast a ScreenRouter es imposible porque la activity es una propiedad que tiene getter abierto o personalizado.

Pensé que tal vez el error es porque la actividad puede ser anulable así que lo intenté:

 if(activity!=null && activity is ScreenRouter) { decoupler.attachRouter(activity) } 

Pero no funcionó y la compilación falló con el mismo error.

Sin embargo, el código siguiente funciona correctamente:

 if(activity is ScreenRouter) { decoupler.attachRouter(activity as ScreenRouter) } 

Su error bien pero por encima no parece explicar nada sobre por qué falla smartcast. No soy un experto de Kotlin, soy un principiante que aprende Kotlin. No encontré documentación en ninguna parte. Este tipo de descripciones de errores hace que Kotlin sea horrible de aprender. ¿Puede alguien explicar en términos simples?

El punto clave aquí es que una propiedad open o una propiedad con un getter personalizado no está garantizado para devolver el mismo valor en las llamadas sucesivas a ella.

Por lo tanto, el compilador no puede estar seguro de que, una vez que se ha comprobado el valor recibido de la propiedad, es seguro asumir que devolverá el mismo objeto o incluso un objeto del mismo tipo si se vuelve a llamar.

Ejemplo (bastante simplificado y sintético, sin embargo):

 open class Base { open val value: List<Int> = ArrayList() } val b : Base = foo() fun printArrayList(list: ArrayList<Int>) { /* ... */ } if (b.value is ArrayList) { // first call printArrayList(b.value) // second call, smart cast is impossible } 

Este código no se compilará, porque printArrayList() espera una ArrayList y b.value está open – eso es lo que obtienes en tu código. Ahora, hagamos una clase derivada que demuestre lo que podría salir mal:

 class Derived : Base() { private var counter = 0 override val value: List<Int> get() { ++counter return if (counter % 2 == 0) ArrayList() else LinkedList() } } val b = Derived() println(b.value.javaClass) // class java.util.LinkedList println(b.value.javaClass) // class java.util.ArrayList 

Aquí está bastante claro que si una propiedad está open , puede ser anulada de manera que las sucesivas llamadas a ella devuelvan valores diferentes. En el ejemplo con printArrayList() hay dos llamadas. Por eso el elenco inteligente no estaría a salvo. Lo mismo ocurre con las propiedades con getters personalizados.

Su ejemplo que realizó una operación as -cast dentro del bloque if funcionó porque el modelo fallaría y lanzaría una ClassCastException si la propiedad devolvió un valor diferente de un tipo no compatible en la segunda llamada y esto preservaría la seguridad de tipo.

Y, por el contrario, si una propiedad val no está open y tiene un getter por defecto que simplemente devuelve el valor del campo de respaldo (que es final en este caso), el compilador puede realizar con seguridad un cast inteligente: si obtiene el valor de La propiedad varias veces es seguro que será el mismo.


Una alternativa es obtener el valor una vez, almacenarlo en una variable local y utilizarlo varias veces en lugar de usar la propiedad de nuevo:

 val list = b.value if (list is ArrayList) { printArrayList(list) // smart cast to ArrayList } 

Ahora, no importa si una propiedad está open , sólo hay una llamada a su getter, y el código entonces opera con el valor que devolvió la llamada. Dado que no puede cambiar, el elenco inteligente es posible aquí.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.