stringtranslate.com

Обратный звонок (компьютерное программирование)

Обратный вызов часто осуществляется на уровне первоначального звонящего.

В компьютерном программировании обратный вызов — это функция , которая хранится в виде данных ( ссылки ) и предназначена для вызова другой функцией — часто обратно на исходный уровень абстракции .

Функция, которая принимает параметр обратного вызова , может быть разработана для обратного вызова перед возвратом к вызывающей стороне, что известно как синхронная или блокирующая . Функция, которая принимает обратный вызов, может быть разработана для сохранения обратного вызова, чтобы ее можно было вызвать обратно после возврата, что известно как асинхронная , неблокирующая или отложенная .

Языки программирования поддерживают обратные вызовы различными способами, такими как указатели на функции , лямбда-выражения и блоки .

Аналогия

Чтобы облегчить понимание концепции, ниже приведена аналогия из реальной жизни.

Клиент посещает магазин, чтобы сделать заказ. Это как первый звонок.

Клиент передает клерку список товаров, чек на покрытие их стоимости и инструкции по доставке. Это параметры первого звонка, включая обратный звонок, который является инструкциями по доставке. Подразумевается, что чек будет обналичен и что инструкции будут выполнены.

Когда сотрудники могут, они доставляют товары в соответствии с инструкциями, что является своего рода ответным звонком.

Примечательно, что доставка не обязательно должна быть выполнена клерком, который принял заказ. Обратный вызов не обязательно должен быть вызван функцией, которая приняла обратный вызов как параметр.

Кроме того, доставка не обязательно должна быть сделана непосредственно клиенту. Обратный вызов не обязательно должен быть вызовом вызывающей функции. Фактически, функция обычно не будет передавать себя как обратный вызов. Некоторые считают использование back вводящим в заблуждение, поскольку вызов (обычно) не является обратным вызовом исходному вызывающему, как это происходит при телефонном звонке .

Использовать

Блокирующий обратный вызов выполняется в контексте выполнения функции, которая передает обратный вызов. Отложенный обратный вызов может выполняться в другом контексте, например, во время прерывания или из потока . Таким образом, отложенный обратный вызов может использоваться для синхронизации и делегирования работы другому потоку.

Обработка событий

Обратный вызов может использоваться для обработки событий. Часто потребляющий код регистрирует обратный вызов для определенного типа события. Когда это событие происходит, вызывается обратный вызов.

Обратные вызовы часто используются для программирования графического пользовательского интерфейса (GUI) программы, которая работает в оконной системе . Приложение предоставляет ссылку на пользовательскую функцию обратного вызова для вызова оконной системой. Оконная система вызывает эту функцию, чтобы уведомить приложение о таких событиях, как щелчки мыши и нажатия клавиш .

Асинхронное действие

Обратный вызов может использоваться для реализации асинхронной обработки. Вызывающий объект запрашивает действие и предоставляет обратный вызов, который будет вызван после завершения действия, что может произойти намного позже запроса.

Полиморфизм

Обратный вызов может быть использован для реализации полиморфизма . В следующем псевдокоде SayHiможет принимать либо , WriteStatusлибо WriteError.

def  WriteStatus ( string  message ):  Write ( stdout ,  message ) def  WriteError ( string  message ):  Write ( stderr ,  message ) def  SayHi ( write ):  write ( "Привет, мир" )

Условное действие

Обратный вызов может использоваться для реализации условного поведения. В следующем псевдокоде, если ведение журнала включено, Logвызывает обратный вызов, getMessageи записывает результат. Но если ведение журнала не включено, то getMessageне вызывается, что экономит время выполнения.

def  Log ( getMessage ):  если  isLoggingEnabled :  message  =  getMessage ();  WriteLine ( message );

Выполнение

Технология обратного вызова реализуется по-разному в зависимости от языка программирования .

В ассемблере , C , C++ , Pascal , Modula2 и других языках функция обратного вызова хранится внутри как указатель функции . Использование одного и того же хранилища позволяет разным языкам напрямую совместно использовать обратные вызовы без слоя взаимодействия во время разработки или выполнения . Например, API Windows доступен через несколько языков, компиляторов и ассемблеров.

C++ также позволяет объектам предоставлять реализацию операции вызова функции. Стандартная библиотека шаблонов принимает эти объекты (называемые функторами ) в качестве параметров.

Многие динамические языки , такие как JavaScript , Lua , Python , Perl [1] [2] и PHP , позволяют передавать объект функции.

Языки CLI, такие как C# и VB.NET, предоставляют типобезопасную инкапсулирующую ссылку на функцию, известную как делегат .

События и обработчики событий , используемые в языках .NET, обеспечивают обратные вызовы.

Функциональные языки обычно поддерживают функции первого класса , которые могут передаваться как обратные вызовы другим функциям, сохраняться как данные или возвращаться из функций.

Многие языки, включая Perl, Python, Ruby , Smalltalk , C++ (11+), C# и VB.NET (новые версии), а также большинство функциональных языков поддерживают лямбда-выражения — неименованные функции со встроенным синтаксисом, которые обычно действуют как обратные вызовы.

В некоторых языках, включая Scheme , ML , JavaScript, Perl, Python, Smalltalk, PHP (начиная с версии 5.3.0), [3] C++ (11+), Java (начиная с версии 8) [4] и многих других, лямбда-выражение может быть замыканием , т. е. может получать доступ к переменным, локально определенным в контексте, в котором определена лямбда-выражение.

В объектно-ориентированном языке программирования , таком как версии Java до появления аргументов с функциональным значением, поведение обратного вызова может быть достигнуто путем передачи объекта, реализующего интерфейс. Методы этого объекта являются обратными вызовами.

В PL/I и ALGOL 60 процедура обратного вызова может потребовать доступа к локальным переменным в содержащих ее блоках, поэтому она вызывается через входную переменную, содержащую как точку входа, так и контекстную информацию. [5]

Пример кода

С

Обратные вызовы имеют широкий спектр применения, например, для сигнализации об ошибках: программа Unix может не захотеть немедленно завершиться, получив SIGTERM , поэтому, чтобы убедиться, что ее завершение обрабатывается правильно, она зарегистрирует функцию очистки как обратный вызов. Обратные вызовы также могут использоваться для управления тем, действует ли функция или нет: Xlib позволяет указывать пользовательские предикаты, чтобы определить, хочет ли программа обрабатывать событие.

В следующем коде C функция PrintNumberиспользует параметр getNumberкак блокирующий обратный вызов. PrintNumberвызывается с помощью GetAnswerToMostImportantQuestionкоторого действует как функция обратного вызова. При запуске вывод: "Значение: 42".

#include <stdio.h> #include <stdlib.h>  void PrintNumber ( int ( * getNumber )( void )) { int val = getNumber (); printf ( "Значение: %d \n " , val ); }         int ПолучитьОтветНаСамыйВажныйВопрос ( void ) { return 42 ; }    int main ( void ) { PrintNumber ( GetAnswerToMostImportantQuestion ); return 0 ; }     

С++

В C++ в дополнение к указателю на функцию можно использовать функтор .

С#

В следующем коде C# метод Helper.Methodиспользует параметр callbackкак блокирующий обратный вызов. Helper.Methodвызывается с помощью Logкоторого действует как функция обратного вызова. При запуске в консоль выводится следующее: "Callback was: Hello world".

public class MainClass { static void Main ( string [] args ) { Helper helper = new Helper (); helper . Method ( Log ); }               static void Log ( string str ) { Console . WriteLine ( $"Обратный вызов был: {str}" ); } }      public class Helper { public void Method ( Action < string > callback ) { callback ( "Привет, мир" ); } }         

Котлин

В следующем коде Kotlin функция askAndAnswerиспользует параметр getAnswerкак блокирующий обратный вызов. askAndAnswerвызывается с помощью getAnswerToMostImportantQuestion, который действует как функция обратного вызова. Запуск этого сообщит пользователю, что ответ на его вопрос — «42».

fun main () { print ( "Введите самый важный вопрос: " ) val question = readLine () askAndAnswer ( question , :: getAnswerToMostImportantQuestion ) }         весело получитьОтветНаСамыйВажныйВопрос (): Int { return 42 }     fun askAndAnswer ( question : String? , getAnswer : () -> Int ) { println ( "Вопрос: $ question " ) println ( "Ответ: ${ getAnswer () } " ) }         

JavaScript

В следующем коде JavaScript функция calculateиспользует параметр operateв качестве блокирующего обратного вызова. calculateвызывается с помощью multiplyи затем с помощью sum, которые действуют как функции обратного вызова.

function calculate ( a , b , opera ) { return opera ( a , b ); } function multiply ( a , b ) { return a * b ; } function sum ( a , b ) { return a + b ; } // выводит 20 alert ( calculate ( 10 , 2 , multiply )); // выводит 12 alert ( calculate ( 10 , 2 , sum ));                         

Метод collection .each()библиотеки jQuery использует переданную ему функцию как блокирующий обратный вызов. Он вызывает обратный вызов для каждого элемента коллекции. Например:

$ ( "li" ). each ( function ( index ) { console.log ( index + " : " + $ ( this ) .text ()); }) ;      

Отложенные обратные вызовы обычно используются для обработки событий от пользователя, клиента и таймеров. Примеры можно найти в addEventListener, Ajax и XMLHttpRequest. [6]

Помимо использования обратных вызовов в исходном коде JavaScript, функции C, которые принимают функцию, поддерживаются через js-ctypes. [7]

Красный и РЕБОЛ

Следующий код REBOL / Red демонстрирует использование обратного вызова.

Красный  [ Заголовок:  "Пример обратного вызова" ]вычислить:  функция  [  num1  [ число! ]  num2  [ число! ]  функция-обратного вызова  [ функция! ] ][  функция-обратного вызова  num1  num2 ]calc-product:  func  [  num1  [ число! ]  num2  [ число! ] ][  num1  *  num2 ]calc-sum:  func  [  num1  [ число! ]  num2  [ число! ] ][  num1  +  num2 ]; оповещения 75, произведение 5 и 15 форма оповещения  вычислить 5 15 :calc-product    ; оповещения 20, сумма 5 и 15 оповещения  формы  расчета  5  15  :calc-sum

Луа

Пример цветового промежуточного изображения с использованием движка Roblox , который принимает необязательный обратный вызов .done:

ждать ( 1 ) локальный  DT  =  ждать ()function  tween_color ( object ,  finish_color ,  fade_time )  local  step_r  =  finish_color.r - object.FoundColor3.r local step_g = finish_color.g - object.FoundColor3.g local step_b = finish_color.b - object.FoundColor3.b local total_steps = 1 / ( DT * ( 1 / fade_time ) ) local performed ; coroutine.wrap ( function ( ) for i = 0 , 1 , DT * ( 1 / fade_time ) do object.BackgroundColor3 = Color3.new ( object.BackgroundColor3.r + ( step_r / total_steps ) , object.BackgroundColor3.g + ( step_g / total_steps ) , object.BackgroundColor3.b + ( step_b / total_steps ) ) wait ( ) end if complete then complete ( ) end end ) ( ) return { done = function ( callback ) performed = callback end } end                                                             tween_color ( some_object ,  Color3.new ( 1,0,0 ) , 1 ) .done ( function () print " Цветовая анимация завершена ! " end )     

Питон

В следующем коде Python функция calculateпринимает параметр operate, который используется как блокирующий обратный вызов. calculateвызывается с помощью squareкоторого действует как функция обратного вызова.

def  square ( val ):  return  val  **  2 def  calculate ( opera ,  val ):  return  opera ( val ) # выходы: 25 calculate ( square ,  5 )

Джулия

В следующем коде Julia функция calculateпринимает параметр operate, который используется как блокирующий обратный вызов. calculateвызывается с помощью squareкоторого действует как функция обратного вызова.

julia> square ( val ) = val ^ 2 square (общая функция с 1 методом) julia> calculate ( opera , val ) = opera ( val ) calculate (общая функция с 1 методом) julia> calculate ( square , 5 ) 25       

Смотрите также

Ссылки

  1. ^ "Perl Cookbook - 11.4. Принятие ссылок на функции". 2 июля 1999 г. Получено 03.03.2008 г.
  2. ^ "Advanced Perl Programming - 4.2 Using Subroutine References". 2 июля 1999 г. Получено 03.03.2008 г.
  3. ^ "Справочник языка PHP - Анонимные функции" . Получено 2011-06-08 .
  4. ^ "Что нового в JDK 8". oracle.com .
  5. ^ Белзер, Джек; Хольцман, Альберт Г.; Кент, Аллен, ред. (1979). Энциклопедия компьютерной науки и технологий: Том 12. Марсель Деккер, inc. стр. 164. ISBN 0-8247-2262-0. Получено 28 января 2024 г. .
  6. ^ "Создание обратных вызовов JavaScript в компонентах". Архив. UDN Web Docs (страница документации). раздел. Функции JavaScript как обратные вызовы. Архивировано из оригинала 2021-12-16 . Получено 2021-12-16 .
  7. ^ Холли, Бобби; Шеперд, Эрик (ред.). «Объявление и использование обратных вызовов». Документация. Mozilla Developer Network (страница документации). Архивировано из оригинала 2019-01-17 . Получено 2021-12-16 .

Внешние ссылки