Tengo en mi proyecto un oyente. Se asigna a drawerLayout
. Me gustaría en la función lambda eliminarlo y anularlo de una vez (secuencialmente). ¿Es posible anular T o this
al final de la función genérica?
Aquí está mi código:
// Usage actionBarListener?.let { drawerLayout.removeDrawerListener(it) // remove listener actionBarListener = null // null it } // Usage expected actionBarListener.releaseAndSetNull { drawerLayout.removeDrawerListener(it) // remove listener and null it } // Generic fun <T> T?.releaseAndSetNull(block: (T?) -> Unit) = apply { this?.apply { block.invoke(this) } this = null // Error: variable expected }
Puedo pensar en varias razones por las que esto nunca podría funcionar.
En primer lugar, la función genérica no sabe si this
trata de var
o val
. Y esta funcionalidad solo podría funcionar en una var
Del mismo modo, no puede saber si es anulable, eso también es un requisito.
Además, incluso puede darse el caso de que no sea una variable la que esté llamando a la función.
como decir que tienes
fun getActionBarListener() { return actionBarListener }
Entonces en otro lugar podrías hacer
getActionBarListener().releaseAndSetNull { drawerLayout.removeDrawerListener(it) // remove listener and null it }
¿Cómo esperas que funcione?
O incluso objetos anónimos podrían llamar a esta función.
Como dijo Ivo Beckers, esta función solo funcionaría en var
s, es decir, KMutableProperty0<T>
. Entonces, podría escribir una extensión en KMutableProperty0<T?>
y usar la reflexión para configurarla, si no le importa usar la reflexión, eso es.
inline fun <T: Any> KMutableProperty0<T?>.releaseAndSetNull(block: (T?) -> Unit) { block(this.get()) this.set(null) } // or if you don't want the block to be called if the property is null: inline fun <T: Any> KMutableProperty0<T?>.releaseAndSetNull(block: (T) -> Unit) { this.get()?.run(block) this.set(null) }
Entonces suponga que tiene una propiedad:
var foo: Int? = 10
Tu puedes hacer:
::foo.releaseAndSetNull { println("Foo: $it") } // or if foo belongs to someObject someObject::foo.releaseAndSetNull { println("Foo: $it") }
Mirando el código de bytes generado, la forma en que esto se implementa (que está sujeto a cambios) es que cada propiedad única a la que hace referencia una referencia de propiedad de esta manera hace que se genere una clase interna. La clase interna tendrá métodos get
y set
que harán su trabajo con un costo adicional mínimo, ya que pueden establecer la propiedad correcta directamente . Entonces, realmente el costo principal es la clase interna adicional que se genera.