descargar - Kotlin: compruebe si se ha inicializado el valor perezoso
kotlin vs scala (3)
¿Hay alguna manera de saber si un valor perezoso se ha inicializado en Kotlin sin inicializarlo en el proceso?
por ejemplo, si tengo un valor perezoso, consultar si es nulo lo instanciaría
val messageBroker: MessageBroker by lazy { MessageBroker() }
if (messageBroker == null) {
// oops
}
Podría potencialmente usar una segunda variable, pero eso parece desordenado.
private var isMessageBrokerInstantiated: Boolean = false
val messageBroker: MessageBroker by lazy {
isMessageBrokerInstantiated = true
MessageBroker()
}
...
if (!isMessageBrokerInstantiated) {
// use case
}
¿Hay alguna forma atractiva de determinar esto, como if (Lazy(messageBroker).isInstantiated())
?
Relacionado (pero no el mismo): ¿Cómo verificar si una variable "lateinit" se ha inicializado?
Desde Kotlin 1.1, puede acceder a un delegado de propiedad directamente utilizando .getDelegate()
.
Puede escribir una propiedad de extensión para una referencia de propiedad que compruebe que tiene un delegado Lazy
que ya se ha inicializado:
/**
* Returns true if a lazy property reference has been initialized, or if the property is not lazy.
*/
val KProperty0<*>.isLazyInitialized: Boolean
get() {
if (this !is Lazy<*>) return true
// Prevent IllegalAccessException from JVM access check on private properties.
val originalAccessLevel = isAccessible
isAccessible = true
val isLazyInitialized = (getDelegate() as Lazy<*>).isInitialized()
// Reset access level.
isAccessible = originalAccessLevel
return isLazyInitialized
}
Luego en el sitio de uso:
val messageBroker: MessageBroker by lazy { MessageBroker() }
if (this::messageBroker.isInitialized) {
// ...
}
Esta solución requiere que kotlin-reflect
esté en el classpath. Con Gradle, utilizar
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
La parte isAccessible = true
es necesaria para .getDelegate()
, porque de lo contrario no puede acceder al campo privado que almacena la referencia del delegado.
Hay una forma, pero tiene que acceder al objeto delegado que devuelve la lazy {}
:
val messageBrokerDelegate = lazy { MessageBroker() }
val messageBroker by messageBrokerDelegate
if(messageBrokerDelegate.isInitialized())
...
isInitialized
es un método público en la interfaz Lazy<T>
, aquí están los docs .
Sobre la base de la solución de teclas de acceso rápido , puede hacer que una propiedad isLazyInitialized (en lugar de una función), sea coherente con la propiedad isInitialized para vars de inicio tardío.
Además, no hay necesidad de manejar el caso nulo.
import kotlin.reflect.KProperty0,
import kotlin.reflect.jvm.isAccessible
val KProperty0<*>.isLazyInitialized: Boolean
get() {
// Prevent IllegalAccessException from JVM access check
isAccessible = true
return (getDelegate() as Lazy<*>).isInitialized()
}