ฟังก์ชั่นโทรกลับคืออะไร?
ฟังก์ชั่นโทรกลับคืออะไร?
คำตอบ:
นักพัฒนามักจะสับสนกับสิ่งที่โทรกลับเป็นเพราะชื่อของสิ่งที่ถูกสาป
ฟังก์ชั่นการโทรกลับเป็นฟังก์ชั่นซึ่งคือ:
วิธีที่ดีในการจินตนาการว่าฟังก์ชันการโทรกลับทำงานได้อย่างไรว่าเป็นฟังก์ชันที่เรียกว่า " ที่ด้านหลัง " ของฟังก์ชันที่ส่งผ่านเข้าไป
อาจเป็นชื่อที่ดีกว่าอาจเป็นฟังก์ชัน"โทรหลังจาก"
โครงสร้างนี้มีประโยชน์มากสำหรับการทำงานแบบอะซิงโครนัสซึ่งเราต้องการให้กิจกรรมเกิดขึ้นทุกครั้งที่เหตุการณ์ก่อนหน้านี้เสร็จสิ้น
pseudocode:
// 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);
}
ผลลัพธ์ถ้าคุณเรียกว่าเหตุการณ์ ():
The number you provided is: 6
I have finished printing numbers.
ลำดับของเอาต์พุตที่นี่มีความสำคัญ เนื่องจากฟังก์ชั่นการโทรกลับถูกเรียกหลังจากนั้น "ฉันพิมพ์หมายเลขเสร็จ" จึงพิมพ์ครั้งสุดท้ายไม่ใช่ครั้งแรก
การโทรกลับถูกเรียกเนื่องจากการใช้งานด้วยภาษาของตัวชี้ หากคุณไม่ได้ใช้งานอย่างใดอย่างหนึ่งไม่ต้องทำงานมากกว่าชื่อ 'โทรกลับ' เพิ่งเข้าใจว่ามันเป็นเพียงชื่อที่ใช้อธิบายวิธีการที่ให้มาเป็นอาร์กิวเมนต์ของวิธีอื่นเช่นเมื่อวิธีการหลักถูกเรียก (เงื่อนไขใด ๆ เช่นการคลิกปุ่ม, ตัวจับเวลาติ๊กเป็นต้น) และเนื้อหาของวิธีการนั้นเสร็จสมบูรณ์ ฟังก์ชันการเรียกกลับถูกเรียกใช้
บางภาษารองรับโครงสร้างที่สนับสนุนฟังก์ชันการเรียกกลับหลายอาร์กิวเมนต์และถูกเรียกโดยยึดตามหน้าที่หลักของฟังก์ชันเสร็จสมบูรณ์ (เช่นมีการโทรกลับหนึ่งครั้งในกรณีที่ฟังก์ชันหลักดำเนินการเสร็จสมบูรณ์แล้วจะถูกเรียกอีกอย่างในกรณีที่ฟังก์ชันหลัก ข้อผิดพลาดเฉพาะ ฯลฯ )
once its parent method completes, the function which this argument represents is then called
สวัสดีครับเกี่ยวกับ ดังนั้นถ้าฟังก์ชั่นถูกส่งผ่านไปยังฟังก์ชั่นอื่นเป็นอาร์กิวเมนต์ แต่เรียกจากกลางของรันไทม์ฟังก์ชั่นของผู้ปกครองเช่นparent(cb) {dostuff1(); cb(); dostuff2()}
นั้นมันจะไม่ถือว่าเป็นcallback
ฟังก์ชั่น?
ฟังก์ชั่นการโทรกลับเป็นฟังก์ชั่นที่คุณให้ไว้กับโค้ดอีกชิ้นหนึ่งซึ่งช่วยให้สามารถเรียกใช้งานโค้ดนั้นได้
ทำไมคุณต้องการทำเช่นนี้? สมมติว่ามีบริการที่คุณต้องเรียกใช้ หากบริการกลับมาทันทีคุณเพียง:
ตัวอย่างเช่นสมมติว่าบริการเป็นfactorial
ฟังก์ชัน เมื่อคุณต้องการมูลค่า5!
คุณจะต้องเรียกใช้factorial(5)
และจะเกิดขั้นตอนต่อไปนี้:
ตำแหน่งการดำเนินการปัจจุบันของคุณถูกบันทึกไว้ (ในสแต็ก แต่นั่นไม่สำคัญ)
การประหารชีวิตจะถูกมอบให้ factorial
เมื่อfactorial
เสร็จแล้วมันจะวางผลลัพธ์ไว้ที่ใดที่หนึ่งที่คุณสามารถไปถึงได้
การประหารจะกลับมาที่เดิม [1]
ทีนี้สมมติว่าfactorial
ใช้เวลานานมากเพราะคุณให้จำนวนมากและจำเป็นต้องทำงานในคลัสเตอร์ซูเปอร์คอมพิวเตอร์บางแห่ง สมมติว่าคุณคาดว่าจะใช้เวลา 5 นาทีในการส่งคืนผลลัพธ์ของคุณ คุณสามารถ:
ออกแบบและใช้งานโปรแกรมในเวลากลางคืนเมื่อคุณหลับเพื่อที่คุณจะไม่ได้จ้องหน้าจอครึ่งเวลา
ออกแบบโปรแกรมของคุณให้ทำสิ่งอื่นในขณะที่factorial
กำลังทำอยู่
หากคุณเลือกตัวเลือกที่สองการโทรกลับอาจเหมาะกับคุณ
ในการใช้ประโยชน์จากรูปแบบการโทรกลับสิ่งที่คุณต้องการคือสามารถโทรfactorial
ด้วยวิธีต่อไปนี้:
factorial(really_big_number, what_to_do_with_the_result)
พารามิเตอร์ที่สอง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-callable และส่งผ่าน URL
คุณได้รับความคิด
ในยุคที่เราเข้าสู่เว็บนี้บริการที่เราเรียกใช้มักจะผ่านเครือข่าย เรามักจะไม่สามารถควบคุมบริการเหล่านั้นได้เช่นเราไม่ได้เขียนพวกเขาเราไม่ดูแลพวกเขาเราไม่สามารถมั่นใจได้ว่าพวกเขาจะขึ้นหรือประสิทธิภาพการทำงาน
แต่เราไม่สามารถคาดหวังให้โปรแกรมของเราบล็อกขณะที่เรากำลังรอให้บริการเหล่านี้ตอบสนอง เมื่อตระหนักถึงสิ่งนี้ผู้ให้บริการมักออกแบบ APIs โดยใช้รูปแบบการโทรกลับ
JavaScript รองรับการโทรกลับได้เป็นอย่างดีเช่นกับ lambdas และ closures และมีกิจกรรมมากมายในโลก JavaScript ทั้งบนเบราว์เซอร์และบนเซิร์ฟเวอร์ มีแม้กระทั่งแพลตฟอร์ม JavaScript ที่พัฒนาขึ้นสำหรับมือถือ
เมื่อเราก้าวไปข้างหน้าพวกเราจำนวนมากขึ้นจะต้องเขียนโค้ดอะซิงโครนัสซึ่งความเข้าใจนี้จะเป็นสิ่งจำเป็น
โปรดทราบว่าการโทรกลับเป็นคำเดียว
หน้าโทรกลับวิกิพีเดียอธิบายได้ดีมาก
อ้างจากหน้าวิกิพีเดีย:
ในการเขียนโปรแกรมคอมพิวเตอร์การเรียกกลับเป็นการอ้างอิงถึงรหัสที่สามารถเรียกใช้งานได้หรือส่วนหนึ่งของรหัสที่สามารถเรียกทำงานได้ซึ่งจะถูกส่งเป็นอาร์กิวเมนต์ไปยังรหัสอื่น สิ่งนี้อนุญาตให้เลเยอร์ซอฟต์แวร์ระดับต่ำกว่าเรียกรูทีนย่อย (หรือฟังก์ชัน) ที่กำหนดในเลเยอร์ระดับสูงกว่า
การตอบสนองของคนธรรมดาจะเป็นว่ามันเป็นฟังก์ชั่นที่ไม่ได้ถูกเรียกโดยคุณ แต่เป็นโดยผู้ใช้หรือโดยเบราว์เซอร์หลังจากเหตุการณ์บางอย่างเกิดขึ้นหรือหลังจากประมวลผลโค้ดบางส่วนแล้ว
ฟังก์ชั่นการโทรกลับเป็นสิ่งที่ควรจะเรียกเมื่อเงื่อนไขตรง แทนที่จะเรียกใช้ทันทีฟังก์ชันเรียกกลับจะถูกเรียกใช้ ณ จุดหนึ่งในอนาคต
โดยทั่วไปจะใช้เมื่อเริ่มงานที่จะเสร็จสิ้นแบบอะซิงโครนัส (เช่นจะเสร็จสิ้นบางเวลาหลังจากที่ฟังก์ชั่นการโทรกลับมา)
ตัวอย่างเช่นฟังก์ชั่นในการร้องขอเว็บเพจอาจต้องการให้ผู้โทรจัดเตรียมฟังก์ชันการโทรกลับที่จะถูกเรียกเมื่อเว็บเพจนั้นดาวน์โหลดเสร็จสิ้น
"...when a condition is met"
แต่ฉันคิดว่าการโทรกลับถูกเรียกเมื่อฟังก์ชั่นผู้ปกครองเสร็จสิ้นการดำเนินการและไม่ได้ขึ้นอยู่กับเงื่อนไข (?)
คำอธิบายการโทรกลับนั้นง่ายที่สุดในแง่ของระบบโทรศัพท์ ฟังก์ชั่นการโทรนั้นคล้ายคลึงกับการโทรหาใครบางคนทางโทรศัพท์ถามคำถามรับคำตอบและวางสาย การเพิ่มการโทรกลับจะเปลี่ยนการเปรียบเทียบเพื่อให้หลังจากถามคำถามคุณจะให้ชื่อและหมายเลขของเธอแก่เธอเพื่อให้เธอสามารถโทรกลับหาคุณได้
- Paul Jakubik "การดำเนินการติดต่อกลับใน C ++"
ฉันเชื่อว่าศัพท์แสง "โทรกลับ" นี้ถูกใช้อย่างไม่เหมาะสมในหลาย ๆ ที่ คำจำกัดความของฉันจะเป็นเช่น:
ฟังก์ชั่นการโทรกลับเป็นฟังก์ชั่นที่คุณส่งให้ใครบางคนและให้พวกเขาเรียกมันในบางช่วงเวลา
ฉันคิดว่าผู้คนเพิ่งอ่านประโยคแรกของคำจำกัดความของ wiki:
การเรียกกลับเป็นการอ้างอิงถึงรหัสที่ใช้งานได้หรือส่วนหนึ่งของรหัสที่สามารถเรียกทำงานได้ซึ่งจะถูกส่งเป็นอาร์กิวเมนต์ไปยังรหัสอื่น
ฉันทำงานกับ API จำนวนมากดูตัวอย่างที่ไม่ดีมากมาย หลายคนมักจะตั้งชื่อตัวชี้ฟังก์ชั่น (การอ้างอิงถึงรหัสที่เรียกใช้งานได้) หรือฟังก์ชั่นที่ไม่ระบุชื่อ (ส่วนหนึ่งของรหัสที่เรียกใช้งานได้) "โทรกลับ" หากพวกเขาเป็นเพียงแค่ฟังก์ชั่น
จริงๆแล้วประโยคที่สองในคำจำกัดความของ wiki แสดงความแตกต่างระหว่างฟังก์ชั่นการโทรกลับและฟังก์ชั่นปกติ:
สิ่งนี้อนุญาตให้เลเยอร์ซอฟต์แวร์ระดับต่ำกว่าเรียกรูทีนย่อย (หรือฟังก์ชัน) ที่กำหนดในเลเยอร์ระดับสูงกว่า
ดังนั้นความแตกต่างคือสิ่งที่คุณกำลังจะผ่านฟังก์ชั่นและวิธีการที่คุณส่งผ่านฟังก์ชั่นจะถูกเรียกว่า หากคุณเพียงแค่กำหนดฟังก์ชั่นและส่งไปยังฟังก์ชั่นอื่นและเรียกมันโดยตรงในส่วนของฟังก์ชั่นนั้นอย่าเรียกมันว่า callback คำจำกัดความกล่าวว่าฟังก์ชั่นที่ส่งผ่านของคุณจะถูกเรียกโดยฟังก์ชัน "ระดับต่ำกว่า"
ฉันหวังว่าผู้คนสามารถหยุดใช้คำนี้ในบริบทที่คลุมเครือมันไม่สามารถช่วยให้ผู้คนเข้าใจดียิ่งขึ้นเท่านั้น
มาทำให้มันง่าย ฟังก์ชั่นโทรกลับคืออะไร?
ตัวอย่างโดยคำอุปมาและอุปมา
ฉันมีเลขา ทุกวันฉันขอให้เธอ: (i) ย่อหย่อนอีเมลขาออกของ บริษัท ที่ที่ทำการไปรษณีย์และหลังจากที่เธอทำนั้นต้องทำ: (ii) สิ่งที่ผมเขียนงานสำหรับเธอที่หนึ่งในผู้บันทึกเหนียว
ทีนี้งานในโน้ตย่อคืออะไร? งานนั้นแตกต่างกันไปในแต่ละวัน
สมมติว่าในวันนี้ฉันต้องการให้เธอพิมพ์เอกสารบางอย่างออกมา ดังนั้นฉันจึงเขียนมันลงบนกระดาษโน๊ตและฉันตรึงมันไว้บนโต๊ะของเธอพร้อมกับจดหมายขาออกที่เธอต้องการโพสต์
สรุป:
ฟังก์ชั่นการโทรกลับเป็นหน้าที่ที่สอง: การพิมพ์เอกสารเหล่านั้น เพราะมันจะทำหลังจากที่จดหมายถูกส่งไปและเพราะโน้ตที่บอกให้เธอพิมพ์เอกสารนั้นจะมอบให้เธอพร้อมกับจดหมายที่เธอต้องการโพสต์
ตอนนี้เรามาผูกคำศัพท์กับการเขียนโปรแกรมกัน
นั่นคือทั้งหมดที่มันเป็น ไม่มีอะไรเพิ่มเติม ฉันหวังว่าจะลบล้างมันสำหรับคุณ - และถ้าไม่ใช่ให้โพสต์ความคิดเห็นและฉันจะพยายามอย่างเต็มที่เพื่ออธิบาย
สิ่งนี้ทำให้การเรียกกลับมีเสียงเหมือนคำสั่ง return ในตอนท้ายของเมธอด
ฉันไม่แน่ใจว่าเป็นสิ่งที่พวกเขา
ฉันคิดว่าการเรียกกลับเป็นจริงการเรียกไปยังฟังก์ชั่นเป็นผลมาจากฟังก์ชั่นอื่นจะถูกเรียกใช้และเสร็จสิ้น
ฉันยังคิดว่าการโทรกลับมีจุดประสงค์เพื่อกล่าวคำปราศรัยที่เกิดขึ้นในรูปแบบของ "เฮ้! สิ่งที่คุณขอใช่ไหมฉันทำไปแล้ว - แค่คิดว่าฉันจะให้คุณรู้ - กลับไปหาคุณ"
โทรกลับคืออะไร
คืออะไรฟังก์ชันการเรียกกลับ ?
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 การเรียกกลับอนุญาตให้โมดูลปลั๊กอินเข้าถึงบริการจากคอนเทนเนอร์ / สภาพแวดล้อม
ความคล้ายคลึง: การโทรกลับ ไม่ตรงกัน ไม่มีการปิดกั้น
ตัวอย่างชีวิตจริงสำหรับการโทรกลับ
โทรหลังจากที่จะเป็นชื่อที่ดีกว่าชื่อโง่, โทรกลับ เมื่อหรือเงื่อนไขตรงกับภายในฟังก์ชั่นให้เรียกฟังก์ชั่นอื่นฟังก์ชั่นการโทรหลังจากที่หนึ่งที่ได้รับเป็นข้อโต้แย้ง
แทนที่จะเขียนโค้ดฟังก์ชั่นด้านในฟังก์ชั่นหนึ่งฟังก์ชั่นหนึ่งเขียนฟังก์ชั่นเพื่อยอมรับฟังก์ชั่นการโทรหลังจากที่เขียนแล้วเป็นอาร์กิวเมนต์ การเรียกหลังจากนั้นอาจถูกเรียกขึ้นอยู่กับการเปลี่ยนแปลงสถานะที่ตรวจพบโดยรหัสในฟังก์ชันที่รับอาร์กิวเมนต์
ฟังก์ชั่นการโทรกลับเป็นฟังก์ชั่นที่คุณระบุให้กับฟังก์ชั่น / วิธีการที่มีอยู่ที่จะเรียกใช้เมื่อการดำเนินการเสร็จสมบูรณ์ต้องมีการประมวลผลเพิ่มเติม ฯลฯ
ยกตัวอย่างเช่นใน Javascript หรือ jQuery ที่เจาะจงมากขึ้นคุณสามารถระบุอาร์กิวเมนต์การเรียกกลับที่จะถูกเรียกเมื่อภาพเคลื่อนไหวสิ้นสุดลง
ใน PHP preg_replace_callback()
ฟังก์ชั่นช่วยให้คุณสามารถระบุฟังก์ชั่นที่จะถูกเรียกเมื่อจับคู่นิพจน์ปกติผ่านสตริงที่จับคู่กันเป็นอาร์กิวเมนต์
ดูรูป :)
โปรแกรมหลักเรียกใช้ฟังก์ชันไลบรารี (ซึ่งอาจเป็นฟังก์ชันระดับระบบด้วย) พร้อมชื่อฟังก์ชันเรียกกลับ ฟังก์ชันการเรียกกลับนี้อาจมีการใช้งานหลายวิธี โปรแกรมหลักเลือกหนึ่งการโทรกลับตามความต้องการ
ในที่สุดฟังก์ชั่นห้องสมุดเรียกฟังก์ชั่นการโทรกลับในระหว่างการดำเนินการ
คำตอบง่ายๆสำหรับคำถามนี้คือฟังก์ชันการเรียกกลับเป็นฟังก์ชันที่เรียกใช้ผ่านตัวชี้ฟังก์ชัน หากคุณผ่านตัวชี้ (ที่อยู่) ของฟังก์ชั่นเป็นอาร์กิวเมนต์ไปยังอีกเมื่อตัวชี้นั้นจะใช้ในการเรียกฟังก์ชั่นมันจะชี้ไปที่มันจะบอกว่ามีการโทรกลับจะทำ
สมมติว่าเรามีฟังก์ชั่น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)` ...
นี่เป็นแนวคิดที่ใช้ในการบรรลุความหลากหลายในการเขียนโปรแกรมเชิงวัตถุ
“ ในการเขียนโปรแกรมคอมพิวเตอร์การเรียกกลับเป็นการอ้างอิงถึงรหัสที่ใช้งานได้หรือส่วนหนึ่งของรหัสที่สามารถเรียกทำงานได้ซึ่งจะถูกส่งเป็นอาร์กิวเมนต์ไปยังรหัสอื่น สิ่งนี้อนุญาตให้เลเยอร์ซอฟต์แวร์ระดับต่ำกว่าเรียกรูทีนย่อย (หรือฟังก์ชัน) ที่กำหนดในเลเยอร์ระดับสูงกว่า” - วิกิพีเดีย
โทรกลับใน C โดยใช้ฟังก์ชั่นตัวชี้
ใน C การเรียกกลับถูกนำไปใช้โดยใช้ Function Pointer ตัวชี้ฟังก์ชั่น - ตามชื่อแนะนำเป็นตัวชี้ไปยังฟังก์ชั่น
ตัวอย่างเช่น 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
/* 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)();
}
ถ้าเรารันโปรแกรมนี้ผลลัพธ์จะเป็น
นี่คือโปรแกรมที่แสดงฟังก์ชันการเรียกกลับภายใน register_callback ด้านใน my_callback ด้านหลังในโปรแกรมหลัก
ฟังก์ชันเลเยอร์ที่สูงกว่าเรียกฟังก์ชันเลเยอร์ที่ต่ำกว่าเป็นการโทรปกติและกลไกการเรียกกลับช่วยให้ฟังก์ชันเลเยอร์ที่ต่ำกว่าเรียกฟังก์ชันเลเยอร์ที่สูงขึ้นผ่านตัวชี้ไปยังฟังก์ชันการเรียกกลับ
การโทรกลับใน Java โดยใช้อินเตอร์เฟส
Java ไม่ได้มีแนวคิดของตัวชี้ฟังก์ชั่นมันใช้กลไกการโทรกลับผ่านกลไกอินเตอร์เฟซที่นี่แทนที่จะเป็นตัวชี้ฟังก์ชั่นเราประกาศอินเตอร์เฟซที่มีวิธีการซึ่งจะถูกเรียกเมื่อ callee เสร็จสิ้นภารกิจของมัน
ให้ฉันสาธิตผ่านตัวอย่าง:
อินเตอร์เฟสการติดต่อกลับ
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
}
}
ฟังก์ชัน Callee หรือฟังก์ชันเลเยอร์ที่ต่ำกว่า
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 ว่างานเฉพาะได้เสร็จสิ้นแล้ว
ความแตกต่างระหว่างกลไกการโทรกลับและกลไก EventListener / 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);
}
}
ดังที่คุณเห็นจากโค้ดด้านบนเรามีอินเทอร์เฟซที่เรียกว่าเหตุการณ์ซึ่งโดยทั่วไปจะแสดงรายการเหตุการณ์ทั้งหมดที่อาจเกิดขึ้นสำหรับแอปพลิเคชันของเรา คลาส Widget เป็นคลาสพื้นฐานสำหรับส่วนประกอบ UI ทั้งหมดเช่นปุ่ม, ช่องทำเครื่องหมาย ส่วนประกอบ UI เหล่านี้เป็นวัตถุที่รับเหตุการณ์จากรหัสเฟรมเวิร์ก คลาสวิดเจ็ตใช้อินเทอร์เฟซเหตุการณ์และมีอินเทอร์เฟซซ้อนกันสองรายการ ได้แก่ OnClickEventListener & OnLongClickEventListener
อินเทอร์เฟซสองเหล่านี้มีหน้าที่รับผิดชอบในการรับฟังเหตุการณ์ที่อาจเกิดขึ้นกับส่วนประกอบ UI ที่ได้รับจาก Widget เช่นปุ่มหรือช่องทำเครื่องหมาย ดังนั้นหากเราเปรียบเทียบตัวอย่างนี้กับตัวอย่างการติดต่อกลับก่อนหน้านี้โดยใช้ Java Interface ทั้งสองอินเตอร์เฟสนี้จะทำงานเป็นอินเตอร์เฟสการติดต่อกลับ ดังนั้นรหัสระดับที่สูงขึ้น (กิจกรรมที่นี่) จะใช้อินเทอร์เฟซทั้งสองนี้ และเมื่อใดก็ตามที่มีเหตุการณ์เกิดขึ้นกับวิดเจ็ตรหัสระดับที่สูงขึ้น (หรือวิธีการของอินเทอร์เฟซเหล่านี้ถูกนำไปใช้ในรหัสระดับที่สูงกว่าซึ่งเป็นที่นี่กิจกรรม) จะถูกเรียก
ตอนนี้ให้ฉันพูดถึงความแตกต่างพื้นฐานระหว่างรูปแบบการโทรกลับและ Eventlistener ดังที่เราได้กล่าวไปแล้วว่าการใช้การโทรกลับผู้ใช้สามารถแจ้งเตือนได้เพียงผู้โทรเดียว แต่ในกรณีของรูปแบบ EventListener ส่วนอื่น ๆ หรือคลาสของแอปพลิเคชันสามารถลงทะเบียนสำหรับเหตุการณ์ที่อาจเกิดขึ้นในปุ่มหรือช่องทำเครื่องหมาย ตัวอย่างของคลาสประเภทนี้คือ OtherClass หากคุณเห็นรหัสของ OtherClass คุณจะพบว่ามันได้ลงทะเบียนตัวเองเป็นผู้ฟังของ ClickEvent ที่อาจเกิดขึ้นในปุ่มที่กำหนดไว้ในกิจกรรม ส่วนที่น่าสนใจคือนอกเหนือจากกิจกรรม (ตัวเรียก), OtherClass นี้จะได้รับการแจ้งเตือนเมื่อใดก็ตามที่มีเหตุการณ์การคลิกเกิดขึ้นบนปุ่ม
ฟังก์ชั่นการโทรกลับเป็นฟังก์ชั่นที่คุณผ่าน (เป็นข้อมูลอ้างอิงหรือตัวชี้) ไปยังฟังก์ชั่นหรือวัตถุบางอย่าง ฟังก์ชั่นหรือวัตถุนี้จะเรียกฟังก์ชั่นนี้กลับมาในภายหลังได้ตลอดเวลาอาจเป็นไปได้หลายครั้งเพื่อวัตถุประสงค์ใด ๆ :
...
ดังนั้นการอธิบายการเรียกกลับเป็นฟังก์ชั่นที่ถูกเรียกเมื่อสิ้นสุดฟังก์ชั่นหรืองานอื่นนั้นทำให้มันง่ายเกินไป (แม้ว่าจะเป็นกรณีการใช้งานทั่วไป)
การเรียกกลับเป็นแนวคิดของการส่งผ่านฟังก์ชันเป็นพารามิเตอร์ไปยังฟังก์ชันอื่นและเรียกใช้ฟังก์ชันนี้เมื่อกระบวนการเสร็จสมบูรณ์
หากคุณได้แนวคิดในการติดต่อกลับผ่านคำตอบที่ดีเยี่ยมฉันขอแนะนำให้คุณเรียนรู้พื้นฐานของแนวคิดนี้
"อะไรทำให้พวกเขา (นักวิทยาศาสตร์คอมพิวเตอร์) พัฒนาการโทรกลับ?" คุณอาจเรียนรู้ปัญหาที่กำลังบล็อค (โดยเฉพาะการปิดกั้น UI) และการโทรกลับไม่ใช่วิธีแก้ไขปัญหาเดียวเท่านั้น มีวิธีแก้ไขปัญหาอื่น ๆ อีกมากมาย (เช่น Thread, Futures, Promises ... )
พื้นที่ใช้งานที่สำคัญอย่างหนึ่งคือคุณลงทะเบียนหนึ่งในฟังก์ชันของคุณเป็นหมายเลขอ้างอิง (เช่นการเรียกกลับ) จากนั้นส่งข้อความ / เรียกใช้ฟังก์ชันเพื่อทำงานหรือประมวลผล ตอนนี้หลังจากการประมวลผลเสร็จสิ้นฟังก์ชั่นที่เรียกว่าจะเรียกฟังก์ชั่นที่ลงทะเบียนของเรา (เช่นตอนนี้โทรกลับเสร็จแล้ว) จึงแสดงให้เราดำเนินการประมวลผล ลิงค์วิกิพีเดีย
นี้อธิบายได้ค่อนข้างดี
ฟังก์ชั่นการโทรกลับหรือที่เรียกว่าฟังก์ชั่นการสั่งซื้อที่สูงขึ้นเป็นฟังก์ชั่นที่ส่งผ่านไปยังฟังก์ชั่นอื่นเป็นพารามิเตอร์และฟังก์ชั่นการโทรกลับถูกเรียก (หรือดำเนินการ) ภายในฟังก์ชั่นหลัก
$("#button_1").click(function() {
alert("button 1 Clicked");
});
ที่นี่เราได้ผ่านฟังก์ชั่นเป็นพารามิเตอร์ไปยังวิธีการคลิก และวิธีการคลิกจะโทร (หรือดำเนินการ) ฟังก์ชั่นการโทรกลับที่เราส่งผ่านไป
ฟังก์ชั่นการโทรกลับฟังก์ชั่ นที่ส่งผ่านไปยังฟังก์ชั่นอื่นเป็นอาร์กิวเมนต์
function test_function(){
alert("Hello world");
}
setTimeout(test_function, 2000);
หมายเหตุ:ในตัวอย่างข้างต้น test_function ที่ใช้เป็นอาร์กิวเมนต์สำหรับฟังก์ชั่น setTimeout