Closure in informatica - definitie, werking en voorbeelden

Leer wat een closure in informatica is: heldere definitie, werking en praktische voorbeelden. Begrijp closures snel en pas ze toe in moderne programmeertalen.

Schrijver: Leandro Alegsa

In de informatica is een closure een functie die een eigen omgeving heeft. In die omgeving bevinden zich één of meer gebonden variabelen: namen die een waarde hebben (bijvoorbeeld een getal, object of andere referentie). De omgeving van de closure bewaart die gebonden variabelen in het geheugen en zorgt ervoor dat de functie ze kan blijven gebruiken, ook nadat de plaats waarin de functie is gemaakt (bijvoorbeeld een andere functie) is beëindigd.

Het begrip closure kreeg die naam door Peter J. Landin in 1964. De programmeertaal Scheme maakte closures breed toepasbaar en populair vanaf ongeveer 1975. Sindsdien hebben veel moderne talen (zoals JavaScript, Python, Ruby en vele functionele talen) closures ingebouwd of ondersteunen ze patronen die hetzelfde effect geven.

Hoe een closure werkt

Belangrijke punten om te begrijpen bij closures:

  • Lexicale scope: een closure legt de omgeving vast op het moment dat de functie wordt gedefinieerd. Dat betekent dat variabelen uit de omringende scope "meegaan" met de functie.
  • Gebonden vs. vrije variabelen: een gebonden variabele is lokaal voor de closure; een vrije variabele is een naam die niet binnen de functie wordt gedefinieerd maar uit een buitenliggende scope komt en door de closure wordt vastgehouden.
  • Levensduur van variabelen: omdat de closure een referentie naar de omgeving behoudt, blijven die variabelen bestaan zolang de closure zelf bereikbaar is. Dit is vaak beheerd door de garbage collector van de taal.
  • By-reference of by-value: in sommige talen verwijst een closure naar de actuele variabele (late binding) en in andere talen worden waarden gekopieerd op het moment van aanmaak (early binding). Dit beïnvloedt hoe veranderingen van buitenaf zichtbaar zijn binnen de closure.

Voorbeelden (kort)

JavaScript (veelvoorkomend patroon: functie-fabriek)

function maakTeller() {   let teller = 0;   return function() {     teller += 1;     return teller;   }; } const tel = maakTeller(); console.log(tel()); // 1 console.log(tel()); // 2 

In dit voorbeeld houdt de anonieme functie de variabele teller vast tussen aanroepen. De binnenste functie is een closure omdat hij de omgeving van maakTeller bewaart.

Python (inner function)

def maak_adder(x):     def adder(y):         return x + y     return adder  add5 = maak_adder(5) print(add5(3))  # 8 

Ook hier behoudt adder de waarde van x uit de buitenste scope.

Let op taalverschillen: in JavaScript zie je soms het probleem van late binding in loops; dat kan worden opgelost met blokscope (let) of door een extra functie te gebruiken.

Toepassingen

  • Encapsulatie van staat zonder objecten (bijv. factory-functies).
  • Callbacks en event-handlers die toegang nodig hebben tot lokale context.
  • Partiële toepassing en currying in functionele programmeerstijlen.
  • Implementatie van iterators en generator-achtige patronen.

Gevolgen voor geheugen en ontwerp

Closures kunnen handig zijn, maar ze houden ook verwijzingen naar omgeving vast. Dat kan onbedoeld geheugen langer vasthouden (bijvoorbeeld grote datastructuren of DOM-elementen in webapplicaties) als de closure niet wordt opgeruimd. Goede praktijk is om bewust te zijn van wat een closure vastlegt en, indien nodig, referenties vrij te geven of geen onnodig grote objecten te sluiten.

Veelvoorkomende misverstanden

Anonieme functies (functies zonder naam) worden soms ten onrechte synoniem gebruikt met closures. Veel talen die anonieme functies ondersteunen, bieden ook closures, maar de twee begrippen zijn niet hetzelfde. Een anonieme functie is alleen een closure als hij een eigen omgeving heeft met ten minste één gebonden variabele. Een anonieme functie zonder eigen omgeving is geen closure. Evenzo kan een closure een naam hebben; een named closure is dus niet per definitie anoniem.

Samengevat: een closure is een functie plus de omgeving die de functie nodig heeft om te kunnen werken buiten de oorspronkelijke scope. Closures zijn fundamenteel in moderne programmeerstijlen en bieden krachtige patronen voor het organiseren van staat, maar vereisen ook aandacht voor scope- en geheugenbeheer.

Sluitingen en eersteklas functies

Waarden kunnen getallen zijn of een ander soort gegevens, zoals letters, of gegevensstructuren die uit eenvoudiger delen bestaan. In de regels van een programmeertaal zijn de eersteklas waarden waarden die aan functies kunnen worden gegeven, door functies kunnen worden teruggegeven, en aan een variabelenaam kunnen worden gebonden. Functies die andere functies aannemen of teruggeven worden hogere-orde functies genoemd. De meeste talen die functies als eerste-orde waarden hebben, hebben ook hogere-orde functies en closures.

Kijk bijvoorbeeld eens naar de volgende Scheme-functie:

; Geef een lijst van alle boeken met ten minste THRESHOLD verkochte exemplaren. (definieer (best-selling-books drempel) (filter (lambda (book) (>= (book-sales book) drempel))      book-list))

In dit voorbeeld is de lambda expressie (lambda (book) (>= (book-sales book) threshold)) onderdeel van de functie best-selling-books. Wanneer de functie wordt uitgevoerd, moet Scheme de waarde van de lambda maken. Het doet dit door een closure te maken met de code voor de lambda en een verwijzing naar de drempel variabele, die een vrije variabele is binnen de lambda. (Een vrije variabele is een naam die niet gebonden is aan een waarde).

De filterfunctie voert de afsluiting vervolgens uit op elk boek in de lijst om te bepalen welke boeken moeten worden teruggegeven. Omdat de afsluiting zelf een verwijzing naar threshold heeft, kan de afsluiting die waarde gebruiken elke keer dat filter de afsluiting uitvoert. De functie filter zelf kan in een geheel apart bestand worden geschreven.

Hier is hetzelfde voorbeeld herschreven in ECMAScript (JavaScript), een andere populaire taal met ondersteuning voor closures:

// Geef een lijst van alle boeken met ten minste 'drempel' verkochte exemplaren. functie bestverkochte-boeken(drempel) { retourneer bookList. filter( functie(boek) { retourneer boek. verkoop >= drempel; } ); }

ECMAScript gebruikt hier het woord function in plaats van lambda, en de Array.filter methode in plaats van de filter functie, maar verder doet de code hetzelfde op dezelfde manier.

Een functie kan een afsluiting creëren en deze teruggeven. Het volgende voorbeeld is een functie die een functie teruggeeft.

In regeling:

; Geef een functie terug die de afgeleide van f benadert ; met behulp van een interval van dx, dat voldoende klein moet zijn. (definieer (afgeleide f dx)) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx))

In ECMAScript:

// Geef een functie terug die de afgeleide van f benadert // met behulp van een interval van dx, dat voldoende klein moet zijn. functie afgeleide(f, dx) { functie(x) {return(f(x + dx) - f(x)) / dx; }; }

De closure omgeving behoudt de gebonden variabelen f en dx nadat de omsluitende functie (afgeleide) terugkomt. In talen zonder afsluitingen zouden deze waarden verloren gaan nadat de afsluitende functie terugkomt. In talen met closures moet een gebonden variabele in het geheugen blijven zolang een closure deze heeft.

Een closure hoeft niet gevormd te worden met een anonieme functie. De programmeertaal Python, bijvoorbeeld, heeft beperkte ondersteuning voor anonieme functies, maar kent wel closures. Bijvoorbeeld, één manier waarop het bovenstaande ECMAScript voorbeeld zou kunnen worden geïmplementeerd in Python is:

# Geef een functie terug die de afgeleide van f # benadert met behulp van een interval van dx, dat voldoende klein moet zijn. def derivative(f, dx): def gradient(x): return (f(x + dx) - f(x)) / dx terug gradiënt

In dit voorbeeld maakt de functie met de naam gradient een sluiting samen met de variabelen f en dx. De buitenste omsluitende functie genaamd afgeleide retourneert deze afsluiting. In dit geval zou een anonieme functie ook werken.

def afgeleide(f, dx): return lambda x: (f(x + dx) - f(x)) / dx

Python moet in plaats daarvan vaak named functions gebruiken, omdat zijn lambda-expressies alleen andere expressies mogen bevatten (code die een waarde teruggeeft) en geen statements (code die effecten heeft maar geen waarde). Maar in andere talen, zoals Scheme, retourneert alle code een waarde; in Scheme is alles een expressie.

Gebruik van sluitingen

Sluitingen hebben vele toepassingen:

  • Ontwerpers van software bibliotheken kunnen gebruikers toestaan om gedrag aan te passen door closures als argumenten aan belangrijke functies door te geven. Bijvoorbeeld, een functie die waarden sorteert kan een closure argument accepteren dat de te sorteren waarden vergelijkt volgens een door de gebruiker gedefinieerd criterium.
  • Omdat closures de evaluatie vertragen - d.w.z. ze "doen" niets totdat ze aangeroepen worden - kunnen ze gebruikt worden om controlestructuren te definiëren. Bijvoorbeeld, alle standaard controle structuren van Smalltalk, inclusief branches (if/dan/else) en loops (while en for), worden gedefinieerd met behulp van objecten waarvan de methoden closures accepteren. Gebruikers kunnen ook gemakkelijk hun eigen controlestructuren definiëren.
  • Er kunnen meerdere functies worden geproduceerd die over dezelfde omgeving sluiten, zodat zij privé met elkaar kunnen communiceren door die omgeving te veranderen (in talen die opdracht toelaten).

In regeling

(definieer foo #f) (definieer bar #f) (laat ((geheim-bericht "geen")) (set! foo (lambda (msg) (set! geheim-bericht msg)) (set! bar (lambda () geheim-bericht))) (display (bar)) ; drukt "geen" af (newline) (foo "ontmoet me bij de dokken om middernacht") (display (bar)) ; drukt "ontmoet me bij de dokken om middernacht" af
  • Closures kunnen worden gebruikt om object systemen te implementeren.

Opmerking: Sommige sprekers noemen elke gegevensstructuur die een lexicale omgeving bindt een closure, maar de term verwijst gewoonlijk specifiek naar functies.

Vragen en antwoorden

V: Wat is een afsluiting in de informatica?


A: Een closure is een functie die een eigen omgeving heeft.

V: Wat bevat de omgeving van een closure?


A: De omgeving van een closure bevat ten minste één gebonden variabele.

V: Wie gaf het idee van closure zijn naam?


A: Peter J. Landin gaf het idee van closure zijn naam in 1964.

V: Welke programmeertaal maakte closures populair na 1975?


A: De programmeertaal Scheme maakte closures populair na 1975.

V: Zijn anonieme functies en closures hetzelfde?


A: Anonieme functies worden soms ten onrechte closures genoemd, maar niet alle anonieme functies zijn closures.

V: Wat maakt een anonieme functie tot een closure?


A: Een anonieme functie is een closure als hij een eigen omgeving heeft met ten minste één gebonden variabele.

V: Is een named closure anoniem?


A: Nee, een named closure is niet anoniem.


Zoek in de encyclopedie
AlegsaOnline.com - 2020 / 2025 - License CC3