
コンピュータ プログラミングにおいて、コールバックとは、データ (参照)として保存され、別の関数 (多くの場合、元の抽象化レイヤー)によって呼び出されるように設計された関数です。
コールバックパラメータを受け入れる関数は、呼び出し元に戻る前にコールバックするように設計できます。これは、同期またはブロッキングと呼ばれます。コールバックを受け入れる関数は、戻った後にコールバックできるようにコールバックを保存するように設計できます。これは、非同期、非ブロッキング、または遅延と呼ばれます。
プログラミング言語は、関数ポインター、ラムダ式、ブロックなど、さまざまな方法でコールバックをサポートします。
類推
この概念を理解しやすくするために、実際の生活からの例えを挙げます。
顧客が注文するために店舗を訪問します。これが最初の電話のようなものです。
顧客は店員に品物のリスト、費用を負担する小切手、配達指示書を渡します。これらは、配達指示書であるコールバックを含む最初の通話のパラメータです。小切手は換金され、指示書に従うことが理解されます。
スタッフが対応できる場合は、コールバックを呼ぶのと同じように、指示通りに商品を配達します。
特に、配達は注文を受けた店員が行う必要はありません。コールバックをパラメータとして受け入れた関数によってコールバックが呼び出される必要はありません。
また、配信は顧客に直接行う必要はありません。コールバックは呼び出し関数に対して行う必要はありません。実際、関数は通常、コールバックとして自身を渡すことはありません。電話の場合のように、呼び出しは (通常) 元の呼び出し元に返されないため、 backの使用は誤解を招くと考える人もいます。
使用
ブロッキング コールバックは、コールバックを渡す関数の実行コンテキストで実行されます。遅延コールバックは、割り込み中やスレッドからなど、異なるコンテキストで実行できます。そのため、遅延コールバックは同期や別のスレッドへの作業の委任に使用できます。
イベント処理
コールバックはイベント処理に使用できます。多くの場合、消費コードは特定の種類のイベントのコールバックを登録します。そのイベントが発生すると、コールバックが呼び出されます。
コールバックは、ウィンドウ システムで実行されるプログラムのグラフィカル ユーザー インターフェイス(GUI)をプログラムするためによく使用されます。アプリケーションは、ウィンドウ システムが呼び出すカスタム コールバック関数への参照を提供します。ウィンドウ システムは、この関数を呼び出して、マウスのクリックやキーの押下などのイベントをアプリケーションに通知します。
非同期アクション
コールバックを使用すると、非同期処理を実装できます。呼び出し元はアクションを要求し、アクションが完了したときに呼び出されるコールバックを提供します。アクションの完了は、要求が行われてからかなり後になる場合があります。
多態性
コールバックを使用してポリモーフィズムを実装できます。次の疑似コードでは、はまたは のSayHiいずれかを取ることができます。
WriteStatusWriteError
def WriteStatus (文字列 メッセージ):
Write ( stdout 、 message )
def WriteError (文字列 メッセージ):
Write ( stderr 、 message )
def SayHi (書き込み):
write ( "Hello world" )
条件付きアクション
コールバックを使用して条件付き動作を実装できます。次の疑似コードでは、ログ記録が有効になっている場合、Logコールバック が呼び出され、getMessage結果が書き込まれます。ただし、ログ記録が有効になっていない場合はgetMessageが呼び出されないため、実行時のコストが節約されます。
def Log ( getMessage ):
isLoggingEnabledの場合 : message = getMessage (); WriteLine ( message );
実装
コールバック技術はプログラミング言語によって異なる方法で実装されます。
アセンブリ、C、C++、Pascal、Modula2などの言語では、コールバック関数は関数ポインターとして内部的に格納されます。同じストレージを使用することで、異なる言語が設計時または実行時の 相互運用性 レイヤーなしでコールバックを直接共有できます。たとえば、Windows API は複数の言語、コンパイラ、アセンブラからアクセスできます。
C++ では、オブジェクトが関数呼び出し操作の実装を提供することもできます。標準テンプレート ライブラリは、これらのオブジェクト (関数オブジェクトと呼ばれる) をパラメーターとして受け入れます。
JavaScript、Lua、Python、Perl [1] [2]、PHPなどの多くの動的言語では、関数オブジェクトを渡すことが可能です。
C#やVB.NETなどのCLI 言語は、delegateと呼ばれる型セーフなカプセル化関数参照を提供します。
.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]
サンプルコード
C
コールバックには、エラー シグナルなど、さまざまな用途があります。Unixプログラムは、 SIGTERM を受信したときにすぐに終了したくない場合があります。そのため、終了が適切に処理されるようにするには、クリーンアップ関数をコールバックとして登録します。コールバックは、関数が動作するかどうかを制御するためにも使用できます。Xlibでは、プログラムがイベントを処理するかどうかを決定するためにカスタム述語を指定できます。
次のCコードでは、関数はPrintNumberパラメータをgetNumberブロッキング コールバックとして使用します。は、コールバック関数として機能する
PrintNumberとともに呼び出されます。実行すると、出力は「値: 42」になります。GetAnswerToMostImportantQuestion
#include <stdio.h> #include <stdlib.h>
void PrintNumber ( int ( * getNumber )( void )) { int val = getNumber (); printf ( "値: %d \n " , val ); }
int GetAnswerToMostImportantQuestion ( void ) { return 42 ; }
int main ( void ) { PrintNumber ( GetAnswerToMostImportantQuestion ); 0 を返す; }
C++
C++ では、関数ポインタに加えて 関数子も使用できます。
C#
次のC#コードでは、メソッドはHelper.Methodパラメータをcallbackブロッキング コールバックとして使用します。はコールバック関数として機能するHelper.Methodとともに呼び出されますLog。実行すると、コンソールに次の内容が書き込まれます: "Callback was: Hello world"。
パブリッククラスMainClass { static void Main ( string [] args ) { Helper helper = new Helper (); helper . Method ( Log ); }
static void Log ( string str ) { Console . WriteLine ( $"コールバックは: {str}" ); } }
パブリッククラスHelper {パブリックvoid Method ( Action < string > callback ) {コールバック( "Hello world" ); } }
コトリン
次のKotlinコードでは、関数はaskAndAnswerパラメータをgetAnswerブロッキング コールバックとして使用します。は、コールバック関数として機能するaskAndAnswerとともに呼び出されますgetAnswerToMostImportantQuestion。これを実行すると、ユーザーに質問の答えが「42」であることが伝えられます。
fun main () { print ( "最も重要な質問を入力してください: " ) val question = readLine () askAndAnswer ( question , :: getAnswerToMostImportantQuestion ) }
fun 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 ) );
jQueryライブラリ.each()のコレクション メソッドは、渡された関数をブロッキング コールバックとして使用します。コレクションの各項目に対してコールバックを呼び出します。例:
$ ( "li" ). each ( function ( index ) { console . log ( index + ": " + $ ( this ). text ()); });
遅延コールバックは、ユーザー、クライアント、タイマーからのイベントを処理するためによく使用されます。例としてはaddEventListener、、Ajax、などがありますXMLHttpRequest。
[6]
JavaScriptソースコードでコールバックを使用するだけでなく、関数を受け取るC関数もjs-ctypes経由でサポートされています。[7]
レッドとREBOL
次のREBOL / Redコードはコールバックの使用を示しています。
- アラートには文字列が必要なので、フォームは計算結果から文字列を生成します。
- get-word! 値 (つまり、:calc-product と :calc-sum) は、関数を評価するのではなく、関数のコードを返すようにインタープリターをトリガーします。
- ブロック内のデータ型参照 [float! integer!] は、引数として渡される値の型を制限します。
赤 [タイトル: 「コールバックの例」]
計算: func [
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
ルア
オプションの .done コールバックを受け取る Robloxエンジンを使用したカラー トゥイーンの例:
待機(1 )
ローカル DT = 待機()
関数 tween_color (オブジェクト、 finish_color 、 fade_time )
ローカル step_r = finish_color.r - object.BackgroundColor3.rローカルstep_g = finish_color.g - object.BackgroundColor3.gローカルstep_b = finish_color.b - object.BackgroundColor3.bローカルtotal_steps = 1 / ( DT * ( 1 / fade_time ) )ローカルcomplete ; 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 ) complete = callback end } end
tween_color ( some_object 、 Color3 。new ( 1 、 0 、 0 )、 1 。done ( function ()
print "カラートゥイーンが終了しました!"
end )
パイソン
次のPythonコードでは、関数はブロッキング コールバックとして使用されるcalculateパラメータを受け入れます。が呼び出され、コールバック関数として機能します。
operatecalculatesquare
def square ( val ):
return val ** 2
def calculate ( opera , val ):
return opera t ( val )
# 出力: 25
calculate ( square , 5 )
ジュリア
次のJuliaコードでは、関数はブロッキング コールバックとして使用されるcalculateパラメーターを受け入れます。が呼び出され、コールバック関数として機能します。
operatecalculatesquare
julia> square ( val ) = val ^ 2 square (メソッドが 1 つの汎用関数) julia> calculate ( operat , val ) = operat ( val ) calculate (メソッドが 1 つの汎用関数) julia> calculate ( square , 5 ) 25
参照
参考文献
- ^ 「Perl クックブック - 11.4. 関数への参照の取得」 1999 年 7 月 2 日. 2008 年 3 月 3 日閲覧。
- ^ 「Advanced Perl Programming - 4.2 サブルーチン参照の使用」 1999 年 7 月 2 日. 2008 年 3 月 3 日閲覧。
- ^ 「PHP 言語リファレンス - 匿名関数」 。2011年 6 月 8 日閲覧。
- ^ 「JDK 8 の新機能」。ora cle.com。
- ^ ベルツァー、ジャック、ホルツマン、アルバート G、ケント、アレン編 (1979)。コンピュータサイエンスとテクノロジー百科事典: 第 12 巻。マルセル デッカー社、p. 164。ISBN 0-8247-2262-0. 2024年1月28日閲覧。
- ^ 「コンポーネントで JavaScript コールバックを作成する」。アーカイブ。UDN Web Docs (ドキュメント ページ)。sec. コールバックとしての JavaScript 関数。2021-12-16 のオリジナルからアーカイブ。2021-12-16に取得。
- ^ Holley, Bobby; Shepherd, Eric (編著). 「コールバックの宣言と使用」. ドキュメント. Mozilla Developer Network (ドキュメントページ). 2019-01-17 にオリジナルからアーカイブ。 2021-12-16に取得。
外部リンク
- 基本的な本能: デリゲートを使用したコールバック通知の実装 - MSDN マガジン、2002 年 12 月
- Javaでコールバックルーチンを実装する
- ASP.NET 1.x でスクリプト コールバック フレームワークを実装する - Code Project、2004 年 8 月 2 日
- C++ メンバー関数と C ライブラリのインターフェイス (2011 年 7 月 6 日のオリジナルからアーカイブ)
- スタイルケーススタディ #2: ジェネリックコールバック
