コールバック関数とは
開発者はしばしば、呼び戻されたものの名前が原因でコールバックが何であるかによって混乱します。
コールバック関数は以下の関数です。
コールバック関数がどのように機能するかを想像するのに良い方法は、それが渡される関数の " 後ろで呼び出される "である関数であるということです。
たぶんもっと良い名前は "call after" 関数になるでしょう。
この構造は、前のイベントが完了したときにアクティビティを実行したいという非同期の動作に非常に役立ちます。
疑似コード:
// A function which accepts another function as an argument
// (and will automatically invoke that function when it completes - note that there is no explicit call to callbackFunction)
funct printANumber(int number, funct callbackFunction) {
printout("The number you provided is: " + number);
}
// a function which we will use in a driver function as a callback function
funct printFinishMessage() {
printout("I have finished printing numbers.");
}
// Driver method
funct event() {
printANumber(6, printFinishMessage);
}
event()を呼び出した場合の結果:
The number you provided is: 6
I have finished printing numbers.
ここでの出力の順序は重要です。コールバック関数は後で呼び出されるので、「番号の印刷が終了しました」が最初ではなく最後に出力されます。
コールバックは、ポインター言語で使用されるため、いわゆるコールバックです。あなたがそれらのうちの1つを使わないならば、「コールバック」という名前を浪費しないでください。親メソッドが呼び出されたとき(ボタンクリック、タイマーティックなどの条件)、そのメソッド本体が完了するように、別のメソッドへの引数として提供されるメソッドを説明する名前にすぎません。その後、コールバック関数が呼び出されます。
いくつかの言語は、複数のコールバック関数の引数がサポートされ、親関数がどのように完了するかに基づいて呼び出されるコンストラクトをサポートします(つまり、親関数が正常に完了した場合に呼び出されます。具体的なエラーなど).
コールバック関数は別のコードに提供する関数で、そのコードから呼び出すことができます。
なぜあなたはこれをしたいのですか?あなたが呼び出す必要があるサービスがあるとしましょう。サービスがすぐに戻ってきたら、あなたは
たとえば、サービスがfactorial
関数であるとします。 5!
の値が必要なときは、factorial(5)
を呼び出します。次の手順が発生します。
あなたの現在の実行場所は保存されます(スタックに保存されますが、それは重要ではありません)
実行はfactorial
に渡されます
factorial
が完了すると、それはあなたがそれに到達できるどこかに結果を置きます
実行はそれがあった場所に戻ります[1]
ここでfactorial
には非常に長い時間がかかったとします。なぜなら、あなたはそれに莫大な数を与えていて、どこかのスーパーコンピューティングクラスタ上で実行する必要があるからです。結果を返すまでに5分かかると予想しているとしましょう。あなたは出来る:
あなたが眠っているときにあなたのデザインを保って夜間にあなたのプログラムを実行してください。
factorial
がしている間に他のことをするようにあなたのプログラムを設計しなさい
2番目のオプションを選択した場合は、コールバックが役に立ちます。
コールバックパターンを悪用するには、次のようにしてfactorial
を呼び出すことができます。
factorial(really_big_number, what_to_do_with_the_result)
2番目のパラメータwhat_to_do_with_the_result
は、factorial
が戻る前にその結果に基づいてそれを呼び出すことを期待して、factorial
に送信する関数です。
はい、これはfactorial
がコールバックをサポートするために書かれている必要があることを意味します。
コールバックにパラメータを渡したいとしましょう。今はできません、呼び出しているわけではないので、factorial
です。それでfactorial
はあなたがあなたのパラメータを渡すことを可能にするために書かれる必要があり、それがそれを呼び出すときそれは単にあなたのコールバックに引き渡されるでしょう。これは次のようになります。
factorial (number, callback, params)
{
result = number! // i can make up operators in my pseudocode
callback (result, params)
}
factorial
がこのパターンを許可するようになったので、コールバックは次のようになります。
logIt (number, logger)
{
logger.log(number)
}
factorial
への呼び出しは次のようになります。
factorial(42, logIt, logger)
logIt
から何かを返したい場合はどうしますか? factorial
はそれに注意を払っていないので、できません。
さて、なぜfactorial
はあなたのコールバックが返すものを返すことができないのですか?
実行はfactorial
が終了したときにコールバックに渡されることを意図しているので、呼び出し元には何も返さないはずです。そして理想的には、それはどういうわけか別のスレッド/プロセス/マシンでその仕事を始めてそしてあなたが続けることができるようにすぐに戻るでしょう。
factorial(param_1, param_2, ...)
{
new factorial_worker_task(param_1, param_2, ...);
return;
}
これは「非同期呼び出し」になりました。つまり、呼び出すとすぐに戻りますが、実際にはまだ実行されていません。それで、あなたはそれをチェックし、そしてそれが終了したときにその結果を得るためのメカニズムを必要としません、そしてあなたのプログラムはその過程でより複雑になりました。
ところで、このパターンを使うとfactorial_worker_task
は非同期にコールバックを起動してすぐに戻ることができます。
答えは、コールバックパターン内に留まることです。書きたいときはいつでも
a = f()
g(a)
そしてf
は非同期的に呼ばれることになっています、代わりに書くでしょう
f(g)
g
はコールバックとして渡されます。
これはあなたのプログラムのフロートポロジを根本的に変えます 、そして慣れるまでに時間がかかります。
あなたのプログラミング言語は、オンザフライで関数を作成する方法をあなたに与えることによってあなたを大いに助けるかもしれません。直前のコードでは、関数g
はprint (2*a+1)
と同じくらい小さいかもしれません。あなたの言語があなたがこれを完全に不必要な名前と署名を持つ別の関数として定義することを要求するならば、あなたがこのパターンをたくさん使うとあなたの人生は不快になるでしょう。
一方、あなたの言語があなたがラムダを作成することを可能にするならば、あなたはずっと良い体調にあります。あなたはそれから何かのように書くことになるでしょう
f( func(a) { print(2*a+1); })
これはとても素晴らしいです。
どのようにしてコールバック関数をfactorial
に渡しますか?まあ、あなたはそれをいくつかの方法で行うことができます。
呼び出された関数が同じプロセスで実行されている場合は、関数ポインタを渡すことができます。
あるいはあなたのプログラムでfn name --> fn ptr
の辞書を管理したいと思うかもしれません、その場合あなたは名前を渡すことができます
多分あなたの言語はあなたがラムダとして可能な場所で関数を定義することを可能にする!内部的にはある種のオブジェクトを作成してポインタを渡すことですが、それについて心配する必要はありません。
おそらくあなたが呼んでいる機能は完全に別のマシン上で走っていて、あなたはそれをHTTPのようなネットワークプロトコルを使って呼んでいます。コールバックをHTTP呼び出し可能関数として公開し、そのURLを渡すことができます。
あなたはアイデアを得ます。
私たちが参入したこのWeb時代には、私たちが呼び出すサービスはしばしばネットワーク上にあります。私たちはしばしばそれらのサービスを制御することができません。すなわち、私たちはそれらを書いていませんでした。
しかし、これらのサービスが応答するのを待っている間は、プログラムがブロックされるとは予想できません。これを認識して、サービスプロバイダーはしばしばコールバックパターンを使用してAPIを設計します。
JavaScriptはコールバックを非常にうまくサポートしています。ラムダとクロージャー付き。そしてJavaScriptの世界には、ブラウザとサーバーの両方で多くの活動があります。モバイル用に開発されているJavaScriptプラットフォームもあります。
私たちが進むにつれて、ますます多くの私たちが非同期コードを書くようになるでしょう。そのためにはこの理解が不可欠です。
コールバックは1つのWordです。
ウィキペディアのコールバックページ 非常によく説明しています。
ウィキペディアのページからの引用:
コンピュータプログラミングでは、コールバックは実行可能コード、または他のコードへの引数として渡される実行可能コードへの参照です。これにより、下位レベルのソフトウェア層が、上位レベルの層で定義されているサブルーチン(または関数)を呼び出すことができます。
素人の応答は、それはあなたによってではなく、特定のイベントが起こった後、またはいくつかのコードが処理された後にユーザーまたはブラウザーによって呼び出される関数であるということでしょう。
コールバック関数は、特定の条件が満たされたときに呼び出されるべきものです。ただちに呼び出されるのではなく、コールバック関数が将来のある時点で呼び出されます。
通常、非同期に終了するタスクが開始されるときに使用されます(つまり、呼び出し元の関数が戻った後しばらくして終了します)。
たとえば、Webページを要求する機能では、Webページのダウンロードが完了したときに呼び出されるコールバック関数を呼び出し元に要求することがあります。
私はこの「コールバック」専門用語が多くの場所で誤って使われてきたと思います。私の定義は次のようになります。
コールバック関数は、あなたが誰かに渡して、ある時点でそれを呼び出せるようにする関数です。
私は人々がWiki定義の最初の文を読んだだけだと思います:
コールバックは、他のコードへの引数として渡される実行可能コードまたは実行可能コードへの参照です。
私はたくさんのAPIを使ってきました。悪い例を見てください。多くの人が関数ポインタ(実行可能コードへの参照)または無名関数(実行可能コードの一部)に「コールバック」という名前を付ける傾向があります。
実際には、Wiki定義の2番目の文だけがコールバック関数と通常の関数の違いを明らかにしています。
これにより、下位レベルのソフトウェア層が、上位レベルの層で定義されているサブルーチン(または関数)を呼び出すことができます。
そのため、違いは、あなたが関数を渡しようとしているのと、渡された関数がどのように呼び出されるのかです。関数を定義して別の関数に渡してその関数本体で直接呼び出しただけの場合は、それをコールバックとは呼ばないでください。定義によると、渡された関数は "低レベル"関数から呼び出されることはないということです。
あいまいな文脈で人々がこの言葉を使うのをやめることができればいいのです。
コールバックは電話システムに関して最も簡単に説明されます。関数呼び出しは、電話で誰かに電話をかけ、質問をし、答えを得て、電話を切るのと似ています。コールバックを追加するとアナロジーが変わり、質問をした後で名前と番号を教えてくれるので、返事をして電話をかけることができます。
- Paul Jakubik、 "C++でのコールバックの実装"
簡単にしましょう。コールバック関数とは何ですか?
たとえ話と類推による例
私は秘書がいます。 (i)郵便局で会社の送信メールを取り下げる、そしてafter彼女はそれをするために:それらのうちの1つの 付箋 。
さて、付箋紙のタスクは何ですか?タスクは日ごとに異なります。
この特定の日に、私は彼女にいくつかの文書を印刷するように要求します。それで私はそれを付箋紙に書き留め、そして私が彼女が投稿する必要がある送信メールと共に彼女の机の上にそれを固定する。
要約すれば:
コールバック機能はその2番目のタスクです。それらの文書を印刷することです。それは、メールが落とされた後に行われ、文書を印刷するように指示する付箋が彼女が投稿する必要があるメールと共に彼女に与えられるからです。
プログラミング語彙と結びつけましょう
それだけです。これ以上何もない。それがあなたのためにそれを片付けたことを願っています - もしそうでなければ、コメントを投稿してください、そして私は明確にするために最善を尽くします。
これにより、コールバックはメソッドの最後にあるreturn文のようになります。
私はそれが彼らが何であるかわからない。
他の関数が呼び出されて完了した結果として、コールバックは実際には関数の呼び出しであると思います。
また、コールバックは、元々の呼び出しに対処するためのものでもあると思います。
Call After は愚かな名前 callback よりも良い名前です。関数内で条件が満たされた場合、または別の関数である Call After 関数を呼び出します。引数は引数として受け取ります。
関数内の内部関数をハードコードするのではなく、すでに記述されている Call After 関数を引数として受け入れる関数を作成します。 Call After は、引数を受け取る関数内のコードによって検出された状態の変化に基づいて呼び出されることがあります。
コールバック関数は、アクションが完了したとき、追加の処理が必要なときなどに呼び出される、既存の関数/メソッドに指定する関数です。
たとえばJavaScript、具体的にはjQueryでは、アニメーションが終了したときに呼び出されるコールバック引数を指定できます。
PHPでは、preg_replace_callback()
関数を使用して、正規表現が一致したときに呼び出される関数を提供し、一致した文字列を引数として渡します。
コールバック とは何ですか?
コールバック関数 とは何ですか?
otherFunction
と呼びましょう)。コールバック関数はotherFunction
の中で呼び出される(または実行される)。 function action(x, y, callback) {
return callback(x, y);
}
function multiplication(x, y) {
return x * y;
}
function addition(x, y) {
return x + y;
}
alert(action(10, 10, multiplication)); // output: 100
alert(action(10, 10, addition)); // output: 20
SOAでは、コールバックによってプラグインモジュールはコンテナ/環境からサービスにアクセスできます。
画像を見てください。
メインプログラムはコールバック関数名でライブラリ関数(システムレベルの関数でもあるかもしれません)を呼び出します。このコールバック関数は複数の方法で実装されるかもしれません。メインプログラムは要件に従って1つのコールバックを選択します。
最後に、ライブラリ関数は実行中にコールバック関数を呼び出します。
関数ポインターを引数として受け取ることができる関数sort(int *arraytobesorted,void (*algorithmchosen)(void))
があるとします。これは、sort()
の実装のある時点で使用できます。それから、ここで関数ポインタalgorithmchosen
によってアドレスされているコードは コールバック関数 と呼ばれます。
利点は、次のようなアルゴリズムを選択できることです。
1. algorithmchosen = bubblesort
2. algorithmchosen = heapsort
3. algorithmchosen = mergesort ...
たとえば、プロトタイプで実装されています。
1. `void bubblesort(void)`
2. `void heapsort(void)`
3. `void mergesort(void)` ...
これは、オブジェクト指向プログラミングで多態性を実現するために使用される概念です。
この質問に対する簡単な答えは、コールバック関数は関数ポインタを通して呼び出される関数であるということです。関数のポインタ(アドレス)を別の引数として渡すと、そのポインタがその関数を呼び出すのに使用されるときにそれが指すと、コールバックが行われたと言われます。
コンピュータプログラミングでは、コールバックは実行可能コード、または他のコードへの引数として渡される実行可能コードへの参照です。これにより、下位レベルのソフトウェア層が、上位レベルの層で定義されているサブルーチン(または関数)を呼び出すことができます。 - Wikipedia
関数ポインタを使ったCでのコールバック
Cでは、コールバックは関数ポインタを使って実装されています。関数ポインタ - 名前が示すように、関数へのポインタです。
例えば、int(* ptrFunc)();です。
ここで、ptrFuncは引数を取らず整数を返す関数へのポインタです。括弧を入れるのを忘れないでください。そうしないと、コンパイラはptrFuncが通常の関数名であると見なします。
これは関数ポインタを説明するためのコードです。
#include<stdio.h>
int func(int, int);
int main(void)
{
int result1,result2;
/* declaring a pointer to a function which takes
two int arguments and returns an integer as result */
int (*ptrFunc)(int,int);
/* assigning ptrFunc to func's address */
ptrFunc=func;
/* calling func() through explicit dereference */
result1 = (*ptrFunc)(10,20);
/* calling func() through implicit dereference */
result2 = ptrFunc(10,20);
printf("result1 = %d result2 = %d\n",result1,result2);
return 0;
}
int func(int x, int y)
{
return x+y;
}
それでは、関数ポインタを使用してCでのコールバックの概念を理解してみましょう。
プログラム全体には、callback.c、reg_callback.h、およびreg_callback.cという3つのファイルがあります。
/* callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* callback function definition goes here */
void my_callback(void)
{
printf("inside my_callback\n");
}
int main(void)
{
/* initialize function pointer to
my_callback */
callback ptr_my_callback=my_callback;
printf("This is a program demonstrating function callback\n");
/* register our callback function */
register_callback(ptr_my_callback);
printf("back inside main program\n");
return 0;
}
/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);
/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
printf("inside register_callback\n");
/* calling our callback function my_callback */
(*ptr_reg_callback)();
}
このプログラムを実行すると、出力は次のようになります。
これはmy_callbackの中でregister_callbackの中でメインプログラムの中に戻って関数コールバックを示すプログラムです。
上位層機能は通常の呼び出しとして下位層機能を呼び出し、コールバックメカニズムは下位層機能がコールバック機能へのポインタを介して上位層機能を呼び出すことを可能にする。
インタフェースを使用したJavaのコールバック
Javaは関数ポインタの概念を持っていませんそれはそのインタフェース機構を通してコールバック機構を実装します
例を挙げて説明しましょう。
コールバックインタフェース
public interface Callback
{
public void notify(Result result);
}
呼び出し元または上位クラス
public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee
//Other functionality
//Call the Asynctask
ce.doAsynctask();
public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}
呼び出し先または下位層の機能
public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}
doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}
EventListenerパターンを使用したコールバック
このパターンは、特定のタスクが終了したことを0〜n個のオブザーバ/リスナに通知するために使用されます。
CallbackメカニズムとEventListener/Observerメカニズムの違いは、コールバックでは、呼び出し先が単一の呼び出し元に通知するのに対し、Eventlisener/Observerでは、呼び出し先はそのイベントに関心を持つすべての人に通知できます。タスクをトリガーしていないアプリケーション)
例を挙げて説明しましょう。
イベントインターフェース
public interface Events {
public void clickEvent();
public void longClickEvent();
}
クラスウィジェット
package com.som_itsolutions.training.Java.exampleeventlistener;
import Java.util.ArrayList;
import Java.util.Iterator;
public class Widget implements Events{
ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>();
ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();
@Override
public void clickEvent() {
// TODO Auto-generated method stub
Iterator<OnClickEventListener> it = mClickEventListener.iterator();
while(it.hasNext()){
OnClickEventListener li = it.next();
li.onClick(this);
}
}
@Override
public void longClickEvent() {
// TODO Auto-generated method stub
Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
while(it.hasNext()){
OnLongClickEventListener li = it.next();
li.onLongClick(this);
}
}
public interface OnClickEventListener
{
public void onClick (Widget source);
}
public interface OnLongClickEventListener
{
public void onLongClick (Widget source);
}
public void setOnClickEventListner(OnClickEventListener li){
mClickEventListener.add(li);
}
public void setOnLongClickEventListner(OnLongClickEventListener li){
mLongClickEventListener.add(li);
}
}
クラスボタン
public class Button extends Widget{
private String mButtonText;
public Button (){
}
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}
クラスチェックボックス
public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}
活動クラス
パッケージcom.som_itsolutions.training.Java.exampleeventlistener;
public class Activity implements Widget.OnClickEventListener
{
public Button mButton;
public CheckBox mCheckBox;
private static Activity mActivityHandler;
public static Activity getActivityHandle(){
return mActivityHandler;
}
public Activity ()
{
mActivityHandler = this;
mButton = new Button();
mButton.setOnClickEventListner(this);
mCheckBox = new CheckBox();
mCheckBox.setOnClickEventListner(this);
}
public void onClick (Widget source)
{
if(source == mButton){
mButton.setButtonText("Thank you for clicking me...");
System.out.println(((Button) mButton).getButtonText());
}
if(source == mCheckBox){
if(mCheckBox.isChecked()==false){
mCheckBox.setCheck(true);
System.out.println("The checkbox is checked...");
}
else{
mCheckBox.setCheck(false);
System.out.println("The checkbox is not checked...");
}
}
}
public void doSomeWork(Widget source){
source.clickEvent();
}
}
その他のクラス
public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}
メインクラス
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}
上記のコードからわかるように、基本的にアプリケーションで発生する可能性があるすべてのイベントをリストしたeventsというインターフェイスがあります。 Widgetクラスは、Button、CheckboxなどのすべてのUIコンポーネントの基本クラスです。これらのUIコンポーネントは、フレームワークコードから実際にイベントを受け取るオブジェクトです。 WidgetクラスはEventsインタフェースを実装し、さらにOnClickEventListenerとOnLongClickEventListenerの2つの入れ子になったインタフェースを持ちます。
これら2つのインタフェースは、ButtonやCheckboxなどのWidget派生UIコンポーネントで発生する可能性があるイベントを監視する役割を果たします。したがって、この例とJavaインタフェースを使用した以前のコールバックの例を比較すると、これら2つのインタフェースはコールバックインタフェースとして機能します。そのため、上位レベルのコード(Here Activity)はこれら2つのインタフェースを実装しています。そして、ウィジェットにイベントが発生するたびに、上位レベルのコード(または上位レベルのコードに実装されているこれらのインターフェースのメソッド、ここではActivity)が呼び出されます。
それでは、コールバックとEventlistenerのパターンの基本的な違いについて説明しましょう。 Callbackを使うと、Calleeは1人のCallerにしか通知できません。しかし、EventListenerパターンの場合、アプリケーションの他の部分またはクラスは、ButtonまたはCheckboxで発生する可能性のあるイベントを登録できます。この種のクラスの例はOtherClassです。 OtherClassのコードを見ると、Activityで定義されたButtonで発生する可能性があるClickEventのリスナーとして登録されていることがわかります。興味深いのは、アクティビティ(呼び出し側)のほかに、このOtherClassにもButtonでクリックイベントが発生するたびに通知されることです。
コールバック関数は、特定の関数またはオブジェクトに(参照またはポインタとして)渡す関数です。この関数またはオブジェクトは、あらゆる目的のために、いつでも、場合によっては複数回、この関数を呼び出します。
...
そのため、コールバックを別の関数またはタスクの最後に呼び出される関数として記述することは、極端に単純化されます(たとえそれが一般的なユースケースであっても)。
コールバックとは、ある関数を別の関数へのパラメータとして渡し、プロセスが完了した後にこの関数を呼び出すという考え方です。
あなたが上記の素晴らしい答えを通してコールバックの概念を得るならば、私はあなたがその考えの背景を学ぶべきであることを勧めます。
「彼ら(コンピュータ科学者)がコールバックを開発した理由は何ですか?」あなたはブロックしている問題を学ぶかもしれません。他にもたくさんの解決策があります(例:スレッド、先物、約束...)。
高階関数とも呼ばれるコールバック関数は、パラメータとして別の関数に渡される関数であり、コールバック関数は親関数内で呼び出される(または実行される)。
$("#button_1").click(function() {
alert("button 1 Clicked");
});
ここではclickメソッドにパラメータとして関数を渡しました。そしてclickメソッドは渡したコールバック関数を呼び出します(または実行します)。
コールバック関数 別の関数に引数として渡された関数。
function test_function(){
alert("Hello world");
}
setTimeout(test_function, 2000);
注: 上記の例では、testTime関数はsetTimeout関数の引数として使用されています。
1つの重要な用法分野はあなたがハンドル(すなわちコールバック)としてあなたの機能の1つを登録してそれから何らかの仕事または処理をするためにメッセージを送るか/何らかの機能を呼び出すことです。処理が完了した後、呼び出された関数は登録された関数を呼び出します(つまり、コールバックが行われます)。これにより、処理が完了したことがわかります。
[ - 。] この /ウィキペディアのリンクは、グラフィカルに説明されています。