stringtranslate.com

Devolución de llamada (programación informática)

Una devolución de llamada suele realizarse al nivel de la persona que llamó originalmente.

En programación de computadoras , una devolución de llamada o función de devolución de llamada es cualquier referencia a un código ejecutable que se pasa como argumento a otro fragmento de código; Se espera que ese código devuelva (ejecute) la función de devolución de llamada como parte de su trabajo. Esta ejecución puede ser inmediata, como en una devolución de llamada sincrónica , o puede ocurrir en un momento posterior, como en una devolución de llamada asincrónica . También se les llama bloqueantes y no bloqueantes .

Los lenguajes de programación admiten devoluciones de llamadas de diferentes maneras, a menudo implementándolas con subrutinas , expresiones lambda , bloques o punteros de función .

Diseño

Hay dos tipos de devoluciones de llamada, que se diferencian en cómo controlan el flujo de datos en tiempo de ejecución: devoluciones de llamada de bloqueo (también conocidas como devoluciones de llamada sincrónicas o simplemente devoluciones de llamada ) y devoluciones de llamada diferidas (también conocidas como devoluciones de llamada asincrónicas ). Si bien las devoluciones de llamada de bloqueo se invocan antes de que regrese una función (como en el ejemplo de C a continuación), se pueden invocar devoluciones de llamada diferidas después de que regresa una función. Las devoluciones de llamada diferidas se utilizan a menudo en el contexto de operaciones de E/S o manejo de eventos, y se llaman mediante interrupciones o por un subproceso diferente en caso de múltiples subprocesos. Debido a su naturaleza, el bloqueo de devoluciones de llamada puede funcionar sin interrupciones o múltiples subprocesos, lo que significa que el bloqueo de devoluciones de llamada no se usa comúnmente para la sincronización o para delegar trabajo a otro subproceso.

Las devoluciones de llamada se utilizan para programar aplicaciones en sistemas de ventanas . En este caso, la aplicación proporciona (una referencia a) una función de devolución de llamada personalizada específica para que la llame el sistema operativo, que luego llama a esta función específica de la aplicación en respuesta a eventos como clics del mouse o pulsaciones de teclas. Una preocupación importante aquí es la gestión de privilegios y seguridad: si bien la función se llama desde el sistema operativo, no debe ejecutarse con los mismos privilegios que el sistema. Una solución a este problema es utilizar anillos de protección.

Implementación

La forma de una devolución de llamada varía según los lenguajes de programación :

Usar

Analogía de la vida diaria

Un cliente visitó una tienda, pero descubrió que el artículo deseado estaba agotado.

Dejan su dirección y un cheque con un empleado, indicándole que cobre el cheque y envíe el artículo a la dirección (registrando una función de devolución de llamada).

Cuando el artículo estuvo disponible, el empleado realiza la instrucción (llamando a la función de devolución de llamada).

C

Las devoluciones de llamada tienen una amplia variedad de usos, por ejemplo en la señalización de errores: es posible que un programa Unix no quiera finalizar inmediatamente cuando recibe SIGTERM , por lo que para asegurarse de que su terminación se maneje correctamente, registraría la función de limpieza como una devolución de llamada. Las devoluciones de llamada también se pueden usar para controlar si una función actúa o no: Xlib permite especificar predicados personalizados para determinar si un programa desea manejar un evento.

El siguiente código C demuestra el uso de devoluciones de llamada para mostrar dos números.

#incluye <stdio.h> #incluye <stdlib.h> #incluye <hora.h>   /* La función que llama toma una única devolución de llamada como parámetro. */ void ImprimirDosNúmeros ( int ( * fuente de números )( void )) { int val1 = Fuente de números (); int val2 = numeroFuente (); printf ( "%d y %d \n " , val1 , val2 ); }              /* Una posible devolución de llamada. */ int overNineThousand ( void ) { return ( rand () % 1000 ) + 9001 ; }        /* Otra posible devolución de llamada. */ int significadoDeVida ( void ) { return 42 ; }    /* Aquí llamamos a PrintTwoNumbers() con tres devoluciones de llamada diferentes. */ int main ( void ) { srand (( sin firmar ) tiempo ( NULL )); /* Inicializa la semilla para la función aleatoria. */ ImprimirDosNúmeros ( & rand ); ImprimirDosNúmeros ( & overNineThousand ); ImprimirDosNúmeros ( & significadoDeLaVida ); devolver 0 ; }         

Salida de ejemplo:

11343 y 145789040 y 957142 y 42

Tenga en cuenta en qué se diferencia esto de simplemente pasar la salida de la función de devolución de llamada a la función de llamada, PrintTwoNumbers() : en lugar de imprimir el mismo valor dos veces, PrintTwoNumbers llama a la devolución de llamada tantas veces como sea necesario. Esta es una de las dos principales ventajas de las devoluciones de llamada.

La otra ventaja es que la función que llama puede pasar cualquier parámetro que desee a las funciones llamadas (no se muestra en el ejemplo anterior). Esto permite ocultar la información correctamente : el código que pasa una devolución de llamada a una función que llama no necesita conocer los valores de los parámetros que se pasarán a la función. Si solo pasara el valor de retorno, entonces los parámetros deberían exponerse públicamente. [ ejemplo necesario ]

Otro ejemplo:

/* * Este es un programa C simple para demostrar el uso de devoluciones de llamada * La función de devolución de llamada está en el mismo archivo que el código de llamada. * La función de devolución de llamada se puede colocar posteriormente en una biblioteca externa como * por ejemplo, un objeto compartido para aumentar la flexibilidad. * */#incluye <stdio.h> #incluye <cadena.h> #incluye <afirmación.h>   typedef struct MyMsg { int appId ; char mensajeCuerpo [ 32 ]; } Mi mensaje ;        void myFunc ( MyMsg * msj ) { if ( ! msg ) { afirmar ( 0 ); devolver ; }          if ( strlen ( msg -> msgBody ) > 0 ) { printf ( "Id de aplicación = %d \n Msg = \" %s \"\n " , msg -> appId , msg -> msgBody ); } else { printf ( "Id. de aplicación = %d \n mensaje = Sin mensaje \n " , mensaje -> appId ); } }             /* * Declaración de variable de un puntero de función */ void ( * callback )( MyMsg * );  int main ( void ) { Mi mensaje msg1 ; mensaje1 . ID de aplicación = 100 ; strcpy ( msg1 . msgBody , "Esto es una prueba." );          /*  * Asigna la dirección de la función "myFunc" a la función  * puntero "callback" (también puede escribirse como "callback = &myFunc;")  */ callback = myFunc ;    /*  * Llamar a la función (también puede escribirse como "(*callback)(&msg1);")  */ callback ( & msg1 );  devolver 0 ; } 

El resultado después de la compilación:

$ gcc  cbtest.c $ ./a.out ID de aplicación = 100 Msg = "Esto es una prueba".

Esta ocultación de información significa que las devoluciones de llamada se pueden utilizar cuando se comunican entre procesos o subprocesos, o mediante comunicaciones serializadas y datos tabulares. [ se necesita aclaración ]

En C++, el functor también se usa comúnmente junto al uso del puntero de función en C.

C#

Una devolución de llamada simple en C# :

clase pública Clase1 { static void Main ( cadena [] args ) { Clase2 c2 = nueva Clase2 ();             // Llamar al método en Class2 con el método de devolución de llamada como parámetro. c2 . Método ( Método de devolución de llamada ); }   // El método de devolución de llamada. Este método imprime la cadena enviada en la devolución de llamada. static void CallbackMethod ( string str ) { Consola . WriteLine ( $"La devolución de llamada fue: {str}" ); } }       public class Class2 { // El método que vuelve a llamar a la persona que llama. // Toma una acción (método) compatible con Action<string> delegado como parámetro. public void Method ( Action < string > callback ) { // Vuelve a llamar al método CallbackMethod en Class1 con el mensaje especificado. devolución de llamada ( "El mensaje a devolver" ); } }            

Kotlin

Una simple devolución de llamada en Kotlin :

fun main () { print ( "Ingrese texto: " ) val pregunta = readLine () respuesta ( pregunta , :: significadoDeLaVida ) }         significado divertido de Life (): Int { retorno 42 }     respuesta divertida ( pregunta : ¿ Cadena?, respuesta : ( ) -> Int ) { println ( "Tu pregunta: $ pregunta " ) println ( "Respuesta: ${ respuesta () } " ) }         

javascript

Las devoluciones de llamada se utilizan en la implementación de lenguajes como JavaScript , incluido el soporte de funciones de JavaScript como devoluciones de llamada a través de js-ctypes [6] y en componentes como addEventListener. [7] Sin embargo, se puede escribir un ejemplo nativo de devolución de llamada sin ningún código complejo:

función calcular ( num1 , num2 , callbackFunction ) { return callbackFunction ( num1 , num2 ); }       función calcProduct ( num1 , num2 ) { return num1 * num2 ; }       función suma calc ( num1 , num2 ) { return num1 + num2 ; } // alertas 150, el producto de 5 y 15 alerta ( calcular ( 10 , 15 , calcProduct )); // alertas 20, la suma de 5 y 15 alerta ( calcular ( 5 , 15 , sumacalc ));           

Primero se define una función calcular con un parámetro destinado a la devolución de llamada: callbackFunction . Luego se define una función que se puede utilizar como devolución de llamada para calcular , calcProduct . Se pueden usar otras funciones para callbackFunction , como calcSum . En este ejemplo, calcular() se invoca dos veces, una vez con calcProduct como devolución de llamada y otra con calcSum . Las funciones devuelven el producto y la suma, respectivamente, y luego la alerta los mostrará en la pantalla.

En este ejemplo primitivo, el uso de una devolución de llamada es principalmente una demostración de principio. Uno podría simplemente llamar a las devoluciones de llamada como funciones regulares, calcProduct(num1, num2) . Las devoluciones de llamada se usan generalmente cuando la función necesita realizar eventos antes de que se ejecute la devolución de llamada, o cuando la función no tiene (o no puede) tener valores de retorno significativos sobre los cuales actuar, como es el caso de JavaScript asincrónico (basado en temporizadores) o solicitudes XMLHttpRequest. . Se pueden encontrar ejemplos útiles en bibliotecas de JavaScript como jQuery , donde el método .each() itera sobre un objeto similar a una matriz, siendo el primer argumento una devolución de llamada que se realiza en cada iteración.

Rojo y REBOL

A partir del JavaScript anterior, así es como se implementaría lo mismo en REBOL o Red (lenguaje de programación) . Observe la presentación más limpia de los datos como código.

Rojo  [ Título:  "Ejemplo de devolución de llamada" ]calcular:  func  [  num1  [ número! ]  número2  [ número! ]  función de devolución de llamada  [ función! ] ][  función de devolución de llamada  num1  num2 ]producto-calc:  func  [  num1  [ número! ]  número2  [ número! ] ][  número1  *  número2 ]suma-calc:  func  [  num1  [ ¡número! ]  número2  [ número! ] ][  número1  +  número2 ]; alertas 75, el producto de 5 y 15 formulario de alerta  calcular 5 15 :calc-product    ; alertas 20, la suma de 5 y 15 forma de alerta  calcula 5 15 :calc-sum    

lua

Un ejemplo de interpolación de color utilizando el motor Roblox que acepta una devolución de llamada .done opcional:

esperar ( 1 ) DT local  = esperar ()  función  tween_color ( objeto ,  color_acabado ,  tiempo_desvanecimiento )  local  step_r  =  color_acabado . r  -  objeto . Color de fondo3 . r  local  paso_g  =  acabado_color . g  -  objeto . Color de fondo3 . g  local  paso_b  =  acabado_color . b  -  objeto . Color de fondo3 . b  local  total_steps  =  1 / ( DT * ( 1 / fade_time ))  local  completado ;  coroutine.wrap ( función ()  para  i  =  0 ,  1 ,  DT * ( 1  /  fade_time )  hacer  objeto . BackgroundColor3  =  Color3 . nuevo  (  objeto . BackgroundColor3 . r  +  ( step_r / total_steps ),  objeto . BackgroundColor3 . g  +  ( step_g / total_steps ),  objeto . BackgroundColor3 . b  +  ( step_b / total_steps )  )  esperar ()  finalizar  si se  completa  y luego  completar () finalizar finalizar )() return { hecho = función ( devolución de llamada ) completada = finalizar la devolución de llamada } finalizar            tween_color ( algún_objeto ,  Color3 . nuevo ( 1 ,  0 ,  0 ),  1 ). hecho ( función ()  imprimir  "¡Interpolación de color finalizada!" fin )

Pitón

Un uso típico de las devoluciones de llamada en Python (y otros lenguajes) es asignar eventos a elementos de la interfaz de usuario.

Aquí hay un ejemplo muy trivial del uso de una devolución de llamada en Python. Primero defina dos funciones, la devolución de llamada y el código de llamada, luego pase la función de devolución de llamada al código de llamada.

>>> def  get_square ( val ): ... """La devolución de llamada.""" ... return val ** 2 ... >>> def llamador ( func , val ): ... return func ( val ) ... >>> llamador ( get_square , 5 ) 25          

Julia

Las funciones en Julia son ciudadanas de primera clase , por lo que simplemente pueden pasarse a funciones de nivel superior para ser utilizadas (llamadas) dentro del cuerpo de esas funciones.

Aquí el mismo ejemplo anterior en Julia:

julia> get_square ( val ) = val ^ 2 # La devolución de llamada get_square (función genérica con 1 método) julia> caller ( func , val ) = func ( val ) caller (función genérica con 1 método) julia> caller ( get_square , 5 ) 25        

Ver también

Referencias

  1. ^ "Libro de cocina de Perl - 11.4. Toma de referencias a funciones". 2 de julio de 1999 . Consultado el 3 de marzo de 2008 .
  2. ^ "Programación avanzada en Perl: 4.2 Uso de referencias de subrutinas". 2 de julio de 1999 . Consultado el 3 de marzo de 2008 .
  3. ^ "Referencia del lenguaje PHP: funciones anónimas" . Consultado el 8 de junio de 2011 .
  4. ^ "Novedades de JDK 8". oracle.com .
  5. ^ Belzer, Jack; Holzman, Albert G; Kent, Allen, eds. (1979). Enciclopedia de informática y tecnología: volumen 12. Marcel Dekker, inc. pag. 164.ISBN _ 0-8247-2262-0. Consultado el 28 de enero de 2024 .
  6. ^ Holley, Bobby; Pastor, Eric (eds.). "Declaración y uso de devoluciones de llamada". Documentos. Mozilla Developer Network (página de documentación). Archivado desde el original el 17 de enero de 2019 . Consultado el 16 de diciembre de 2021 .
  7. ^ "Creación de devoluciones de llamada de JavaScript en componentes". Archivo. UDN Web Docs (página de documentación). segundo. JavaScript funciona como devoluciones de llamada. Archivado desde el original el 16 de diciembre de 2021 . Consultado el 16 de diciembre de 2021 .

enlaces externos