Kotlin. Lambda vs referencia de funci贸n

Kotlin ha sido durante mucho tiempo el lenguaje de programaci贸n principal en Android. Una de las razones por las que me gusta este lenguaje es que sus funciones son objetos de primera clase . Es decir, una funci贸n puede pasarse como par谩metro, usarse como valor de retorno y asignarse a una variable. Adem谩s, en lugar de una funci贸n, puede pasar un llamado lambda . Y recientemente tuve un problema interesante relacionado con reemplazar la lambda con una referencia de funci贸n.





Imagina que tenemos una clase Button



que recibe una funci贸n en el constructor como par谩metroonClick







class Button(
    private val onClick: () -> Unit
) {
    fun performClick() = onClick()
}
      
      



Y hay una clase ButtonClickListener



que implementa la l贸gica de los clics de los botones.





class ButtonClickListener {
    fun onClick() {
        print(" ")
    }
}
      
      



En la clase ScreenView



, almacenamos una variable lateinit var listener: ButtonClickListener



y creamos un bot贸n, al que se le pasa una lambda, dentro del cual se llama al m茅todoButtonClickListener.onClick







class ScreenView {
    lateinit var listener: ButtonClickListener
    val button = Button { listener.onClick() }
}
      
      



En el m茅todo, main



creamos un objeto ScreenView



, inicializamos la variable listener



y simulamos hacer clic en el bot贸n





fun main() {
    val screenView = ScreenView()
    screenView.listener = ButtonClickListener()
    screenView.button.performClick()
}
      
      



Despu茅s de iniciar la aplicaci贸n, todo funciona bien y se muestra la l铆nea "Bot贸n presionado".





ScreenView



, - val button = Button { listener.onClick() }



. , ButtonClickListener.onClick



onClick: () -> Unit



, , , .





class ScreenView {
    lateinit var listener: ButtonClickListener
    val button = Button(listener::onClick)
}
      
      



- listener





Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property listener has not been initialized
at lambdas.ScreenView.<init>(ScreenView.kt:6)
at lambdas.ScreenViewKt.main(ScreenView.kt:10)
at lambdas.ScreenViewKt.main(ScreenView.kt)
      
      



, Java . .





Function0



invoke



, . - listener.onClick()







private final Button button = new Button((Function0)(new Function0() {
    public final void invoke() {
       ScreenView.this.getListener().onClick();
    }
}));
      
      



, listener



.





. Function0



, invoke()



, , onClick



this.receiver



. receiver



Function0



listener



, listener



lateinit



, receiver



- listener



null



, . .





Button var10001 = new Button;
Function0 var10003 = new Function0() {
   public final void invoke() {
      ((ButtonClickListener)this.receiver).onClick();
   }
};
ButtonClickListener var10005 = this.listener;
if (var10005 == null) {
   Intrinsics.throwUninitializedPropertyAccessException("listener");
}

var10003.<init>(var10005);
var10001.<init>((Function0)var10003);
this.button = var10001;
      
      



Es decir, la diferencia entre una lambda y una referencia de funci贸n es que cuando se pasa una referencia de funci贸n, la variable a cuyo m茅todo nos referimos se fija en la creaci贸n y no en la ejecuci贸n, como sucede cuando se pasa una lambda.





Esto conduce al siguiente problema interesante: 驴Qu茅 se imprimir谩 despu茅s de que se inicie el programa?





class Button(
    private val onClick: () -> Unit
) {
    fun performClick() = onClick()
}

class ButtonClickListener(
    private val name: String
) {
    fun onClick() {
        print(name)
    }
}

class ScreenView {
    var listener = ButtonClickListener("First")
    val buttonLambda = Button { listener.onClick() }
    val buttonReference = Button(listener::onClick)
}

fun main() {
    val screenView = ScreenView()
    screenView.listener = ButtonClickListener("Second")
    screenView.buttonLambda.performClick()
    screenView.buttonReference.performClick()
}
      
      



  1. FirstFirst







  2. FirstSecond







  3. SecondFirst







  4. SecondSecond







Responder

3





Gracias por leer, espero que alguien est茅 interesado y sea 煤til.








All Articles