Takaisinsoitto ( englanniksi call - call, englanniksi back - reverse) tai takaisinsoittotoiminto ohjelmoinnissa - suoritettavan koodin välittäminen yhdeksi toisen koodin parametreista . Takaisinkutsu sallii funktion suorittaa argumenteissa määritetyn koodin, kun sitä kutsutaan. Tämä koodi voidaan määrittää muissa koodikonteksteissa , eikä sitä voida kutsua suoraan tästä funktiosta. Joidenkin algoritmisten tehtävien syötteenä ei ole vain numeroita tai objekteja, vaan myös toimintoja (algoritmeja), jotka määritetään luonnollisesti takaisinkutsuiksi.
Takaisinsoittokonseptilla on monia sovelluksia. Esimerkiksi joidenkin algoritmien (funktioiden) osatehtävänä on laskea hajautusarvo merkkijonosta. Argumenteissa algoritmia (funktiota) käynnistettäessä on kätevää määrittää, mitä funktiota käytetään hash-arvojen laskemiseen.
Toinen esimerkki algoritmista, jolle on luonnollista antaa funktio argumenttina, on algoritmi jonkin objektivaraston läpikäymiseksi ja jokaiseen objektiin kohdistamalla jokin toiminto. Takaisinsoitto voi toimia tämän toimintona (algoritmina).
Takaisinsoitto-ohjelmointitekniikka ohjelmointikielillä, kuten C , on yksinkertainen. Kun päätoimintoa kutsutaan , se yksinkertaisesti välitetään osoitin takaisinsoittotoimintoon. Klassinen esimerkki on funktio qsortstdlib -kirjastosta . Tämä funktio lajittelee joukon samanpituisia tavulohkoja. Argumentteina se vastaanottaa taulukon ensimmäisen elementin osoitteen, taulukon lohkojen lukumäärän, tavulohkon koon ja osoittimen funktioon, joka vertaa kahta tavulohkoa. Tämä vertailutoiminto on takaisinsoittotoiminto tässä esimerkissä:
#include <stdlib.h> // funktio kokonaislukujen vertailuun modulo int vertaa_abs ( const void * a , const void * b ) { int a1 = * ( int * ) a ; int b1 = * ( int * ) b ; paluu abs ( a1 ) - abs ( b1 ); } int main () { int koko = 10 ; int m [ koko ] = { 1 , -3 , 5 , -100 , 7 , 33 , 44 , 67 , -4 , 0 }; // taulukon m lajittelu nousevissa moduuleissa qsort ( m , size , sizeof ( int ), vertaa_abs ); paluu 0 ; }Voit ajatella takaisinsoittoa toimintona, joka välitetään argumenttina johonkin päämenettelyyn. Ja tämä toiminta voidaan nähdä seuraavasti:
Yllä oleva esimerkki vastaa täsmälleen ensimmäistä tapausta. Tapaus, jossa takaisinsoittoa käytetään "puhelinliittymänä", kuvastaa koodia, jossa annetaan toiminto tietyn signaalin käsittelemiseksi:
#include <stdio.h> #include <signal.h> haihtuva sig_atomic_t br = 1 ; tyhjä merkki ( int signum ) { br = 0 ; } int main ( int argc , char * argv []) { signaali ( SIGINT , sig ); printf ( "Paina näppäinyhdistelmää pysäyttääksesi ohjelman \n " ); kun ( br ); printf ( "SIGINT vastaanotettu, poistu \n " ); paluu 0 ; }Joissakin ohjelmointikielissä, kuten Common Lisp , Erlang , Scheme , Clojure , PHP , JavaScript , Perl , Python , Ruby ja muissa, on mahdollista rakentaa nimettömiä (nimeämättömiä) toimintoja ja sulkemisfunktioita suoraan pääfunktion kutsulausekkeessa, ja tätä mahdollisuutta käytetään laajasti.
AJAX-tekniikassa , kun teet asynkronisen pyynnön palvelimelle, sinun on määritettävä takaisinsoittotoiminto, joka kutsutaan heti, kun vastaus pyyntöön saapuu. Usein tämä toiminto määritellään "paikallaan" antamatta sille mitään erityistä nimeä:
uusi Ajax . Request ( 'http://example.com/do_it' , { method : 'post' , onSuccess : function ( kuljetus ) { // ikkunan kutsuma toiminto . alert ( "Valmis!" ); // jos pyyntö onnistui } , // onFailure : toiminto () { // ikkunan kutsuma toiminto . hälytys ( "Virhe!" ); // pyynnöstä suoritusvirhe } });Takaisinsoittotoimintoa käytetään myös Observer - suunnittelumallissa . Joten esimerkiksi Prototyyppikirjastoa käyttämällä voit luoda "tarkkailijan", joka tarkkailee tunnisteella varustetun elementin napsautuksia ja kirjoittaa elementin sisään viestin, kun tapahtuma vastaanotetaan : "my_button""message_box"
tapahtuma . tarkkailla ( $ ( "my_button" ), 'click' , function () { $ ( "viestilaatikko" ). innerHTML = "Napsautit painiketta!" });Takaisinsoittofunktio on vaihtoehto funktiopolymorfismille , eli sen avulla voit luoda yleisempää tarkoitusta varten olevia funktioita sen sijaan, että luotaisiin sarja funktioita, jotka ovat rakenteeltaan samanlaisia, mutta jotka eroavat vain tietyistä kohdista suoritettavissa alitehtävissä. Funktioita, jotka ottavat muita toimintoja argumentteina tai palauttavat funktioita tuloksena, kutsutaan korkeamman asteen funktioiksi . Takaisinsoittotekniikalla on tärkeä rooli koodin uudelleenkäytön saavuttamisessa .
Ymmärtääksesi paremmin takaisinsoiton käytön syitä, harkitse yksinkertaista tehtävää suorittaa seuraavat toiminnot numeroluettelolle: tulosta kaikki luvut, neliötä kaikki luvut, suurenna kaikkia lukuja yhdellä, aseta kaikki elementit nollaan. On selvää, että algoritmit näiden neljän toiminnon suorittamiseksi ovat samankaltaisia - tämä on silmukka, joka ohittaa kaikki luettelon elementit jollakin toiminnolla silmukan rungossa, jota sovelletaan jokaiseen elementtiin. Tämä on yksinkertainen koodi, ja periaatteessa voit kirjoittaa sen 4 kertaa. Mutta tarkastellaan monimutkaisempaa tapausta, jossa luetteloa ei ole tallennettu muistiin, vaan levylle ja useat prosessit voivat toimia luettelon kanssa samanaikaisesti ja on tarpeen ratkaista elementtien synkronointiongelmat (useita prosesseja voi suorittaa erilaisia tehtäviä - poistaa joitain elementtejä luettelosta, lisätä uusia, muuttaa luettelossa olevia kohteita). Tässä tapauksessa luettelon kaikkien elementtien läpikäyminen on melko monimutkaista koodia, jota ei haluaisi kopioida useita kertoja. Olisi oikeampaa luoda yleiskäyttöinen funktio listan elementtien läpikulkua varten ja antaa ohjelmoijien irtautua läpikulkualgoritmin toiminnasta ja kirjoittaa vain takaisinsoittofunktio listan yksittäisen elementin käsittelemiseksi.
Ohjelmiston jäsentäminen takaisinsoittotoimintojen avulla on erittäin kätevä ja laajalti käytetty lähestymistapa, koska muuttumattoman (myös suljetun) koodin ohjelman käyttäytymistä voidaan muuttaa hyvin laajasti. Tämä toteutetaan kahdella tavalla - joko funktion "vaihtoehtoisella toteutuksella" tai "lisäämällä toinen toiminto soittoketjuun".
Yleensä kehittäjä ei toteuta takaisinkutsujen kautta kaikkia ohjelman toimintoja, vaan vain niitä, joita laajennuksilla on tarkoitus laajentaa tai muokata . Liitännäisten liittämiseen tarjotaan erityinen menettely, joka korvaa kehittäjän "standardi" käänteisfunktiot vaihtoehtoisilla laajennuksen funktioilla.
Tunnetuin esimerkki tästä lähestymistavasta on Microsoft Windows -käyttöjärjestelmä , jossa takaisinsoittotoimintoja kutsutaan "käsittelijäksi" ("käsittelijä"), ja on mahdollista lisätä ylimääräinen toiminto kahden tavallisen toiminnon väliin. Tätä lähestymistapaa kutsutaan "tapahtumien sieppaukseksi" ja sitä käytetään esimerkiksi: virustentorjuntaohjelmat tarkistamaan tiedostot, joita käytetään; virukset näppäimistöltä syötettyjen merkkien lukemiseen; verkkosuodattimet tilastojen keräämiseen ja pakettien estämiseen.
Nykyaikaisissa Unix- ja Linux -järjestelmissä on mahdollista ladata ja purkaa dynaamisesti ydinmoduuleja, jotka myös perustuvat takaisinsoittotoimintoihin. Samaan aikaan on olemassa moduuli (ytimen laajennus) FUSE , joka puolestaan tarjoaa tavallisille käyttäjäohjelmille mahdollisuuden palvella (siepata) pyyntöjä virtuaalisille tiedostojärjestelmille.
Ohjelmistoissa joskus tapahtuu ohjelmien hajoamista, joka perustuu täysin takaisinsoittotoimintoihin, mikä huonontaa hieman koodin luettavuutta, mutta antaa laajennuksille maksimaaliset mahdollisuudet. Esimerkki tällaisesta tuotteesta on DokuWiki .
Edut:
Virheet: