Prejsť na obsah
Domov

Uzáver v informatike: definícia, vlastnosti a význam

Uzáver (closure) je funkcia spolu s jej lexikálnym prostredím; uchováva viazané premenné a umožňuje enkapsuláciu stavu v jazykoch s prvotriednymi funkciami.

Uzáver je v programovaní špecifický druh funkcie, ktorý okrem svojho telesa obsahuje aj referenciu na svoj lexikálny kontext — teda na premenné, ktoré boli zviazané v čase vytvorenia. Inak povedané, uzáver kombinujesámotnú funkciu s prostredím, ktoré ukladá hodnoty jej viazaných mien. Táto vlastnosť umožňuje, aby funkcia „pamätala“ stav medzi volaniami bez použitia globálnych premenných.

Hlavné charakteristiky

  • Lexikálne viazanie: uzáver drží odkazy na premenné zo svojho vonkajšieho bloku, nie na premenné podľa mena pri volaní.
  • Životnosť údajov: hodnota viazaných premenných žije tak dlho, ako žije uzáver, aj keď pôvodný rozsah (scope) skončil.
  • Prvotriedne funkcie: jazyky, ktoré umožňujú priradzovať funkcie do premenných, vracať ich z iných funkcií a odovzdávať ako argumenty, zvyčajne podporujú uzávery.

Krátka história a pôvod pojmu

Pojem "closure" sa pripisuje Petru J. Landinovi v 60. rokoch 20. storočia. V praktickom programovaní sa uzávery výraznejšie rozšírili so vzostupom funkcionálnych jazykov; jeden z kľúčových momentov bol popularizovaný jazykom Scheme, často odkazovaným v literatúre aj cez historické materiály o Scheme. Dnes sú uzávery súčasťou mnohých moderných jazykov od skriptovacích po silno typované jazyky.

Použitie a príklady významu

Uzávery sa využívajú tam, kde je potrebné udržať súkromný stav alebo vytvoriť funkcie s predplnenými argumentmi (partial application). Typické scenáre zahŕňajú:

  1. Funkčné továrne — funkcia vracia inú funkciu, ktorá si pamätá parametre z okolitého volania.
  2. Callbacky a event handlery — keď callback potrebuje prístup k lokálnym hodnotám zo svojho pôvodného kontextu.
  3. Enkapsulácia stavu bez tried — uzávery umožnia „súkromné“ premenné bez použitia objektov.

Rozdiely a bežné omyly

Nie každý anonymný (bezmenný) blok kódu je uzáver. Anonymná funkcia je uzáver iba vtedy, keď zachytáva aspoň jednu viazanú premennú zo svojho vonkajšieho prostredia. Ak anonymná funkcia neodkazuje na žiadne vonkajšie premenné, nejde o uzáver. V praxi sa preto často zamieňajú pojmy anonymná funkcia a uzáver, čo vedie k terminologickým nejasnostiam.

Implementačné poznámky a obmedzenia

Realizácia uzáverov závisí od runtime a kompilátora jazyka. Niektoré implementácie alokujú zachytené premenné na halde, iné používajú optimalizácie pre prípad, že uzávery nie sú dlho živé. Pri práci s uzávierkami treba byť opatrný pri zdieľaní premenných medzi viacerými uzávermi (tzv. capturing by reference vs. by value), pretože môže viesť k neočakávanému správaniu, ak sa hodnota v priebehu času mení.

Ďalšie informácie a technické detaily možno nájsť v literatúre a online zdrojoch: úvod k uzáverom, príklady implementácií v rôznych jazykoch: funkcie a uzávery, ukážky v jazyku: Scheme a ďalšie porovnania: história a vývoj. Pre rozdiel medzi anonymnými funkciami a uzávermi pozrite: anonymné funkcie.

Uzávery a funkcie prvej triedy

Hodnoty môžu byť čísla alebo iný typ údajov, napríklad písmená, alebo dátové štruktúry zložené z jednoduchších častí. V pravidlách programovacieho jazyka sú hodnotami prvej triedy hodnoty, ktoré môžu byť zadané funkciám, vrátené funkciami a viazané na meno premennej. Funkcie, ktoré prijímajú alebo vracajú iné funkcie, sa nazývajú funkcie vyššieho rádu. Väčšina jazykov, ktoré majú funkcie ako hodnoty prvej triedy, má aj funkcie vyššieho rádu a uzávery.

Pozrite sa napríklad na nasledujúcu funkciu schémy:

; Vráťte zoznam všetkých kníh, z ktorých sa predalo aspoň TISÍC výtlačkov. (define (best-selling-books threshold) (filter (lambda (book) (>= (book-sales book) threshold)) book-list))

V tomto príklade je lambda výraz (lambda (book) (>= (book-sales book) threshold)) súčasťou funkcie best-selling-books. Pri spustení funkcie musí Scheme vytvoriť hodnotu lambda výrazu. Urobí to tak, že vytvorí uzáver s kódom pre lambdu a odkazom na premennú threshold, ktorá je voľnou premennou vnútri lambdy. (Voľná premenná je meno, ktoré nie je viazané na hodnotu.)

Funkcia filtra potom vykoná uzáver na každej knihe v zozname, aby vybrala knihy, ktoré sa majú vrátiť. Keďže samotný uzáver má odkaz na prah, uzáver môže túto hodnotu použiť pri každom spustení funkcie filter. Samotná funkcia filter môže byť zapísaná v úplne samostatnom súbore.

Tu je ten istý príklad prepísaný v jazyku ECMAScript (JavaScript), ďalšom populárnom jazyku s podporou uzáverov:

// Vráťte zoznam všetkých kníh, ktorých predaj dosiahol aspoň 'prahovú' hodnotu. function bestSellingBooks(threshold) { return bookList. filter( function(book) { return book. sales >= threshold; }     ); }

ECMAScript tu používa slovo function namiesto lambda a metódu Array.filter namiesto funkcie filter, ale inak kód robí tú istú vec rovnakým spôsobom.

Funkcia môže vytvoriť uzáver a vrátiť ho. Nasledujúci príklad je funkcia, ktorá vracia funkciu.

V schéme:

; Vráťte funkciu, ktorá aproximuje deriváciu f ; pomocou intervalu dx, ktorý by mal byť primerane malý. (define (derivative f dx) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx)))

V ECMAScripte:

// Vráťte funkciu, ktorá aproximuje deriváciu f // pomocou intervalu dx, ktorý by mal byť primerane malý. funkcia derivative(f, dx) { return function(x) { return (f(x + dx) - f(x)) / dx; }; }; }

Prostredie uzáveru zachováva viazané premenné f a dx po návrate uzatvárajúcej funkcie (derivácie). V jazykoch bez uzáverov by sa tieto hodnoty po návrate obklopujúcej funkcie stratili. V jazykoch s uzávermi musí byť viazaná premenná uchovávaná v pamäti dovtedy, kým ju má nejaký uzáver.

Uzáver nemusí byť vytvorený pomocou anonymnej funkcie. Napríklad programovací jazyk Python má obmedzenú podporu anonymných funkcií, ale má uzávery. Jedným zo spôsobov, ako by sa dal vyššie uvedený príklad ECMAScriptu implementovať v jazyku Python, je napríklad:

# Vráťte funkciu, ktorá aproximuje deriváciu f # pomocou intervalu dx, ktorý by mal byť primerane malý. def derivative(f, dx): def gradient(x): return (f(x + dx) - f(x)) / dx return gradient

V tomto príklade funkcia s názvom gradient tvorí uzáver spolu s premennými f a dx. Vonkajšia obklopujúca funkcia s názvom derivácia vracia tento uzáver. V tomto prípade by fungovala aj anonymná funkcia.

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

Python musí často používať pomenované funkcie, pretože jeho lambda výrazy môžu obsahovať len iné výrazy (kód, ktorý vracia hodnotu) a nie príkazy (kód, ktorý má účinky, ale nemá hodnotu). V iných jazykoch, napríklad v Scheme, však všetok kód vracia hodnotu; v Scheme je všetko výraz.

Použitie uzáverov

Uzávery majú mnoho využití:

  • Návrhári softvérových knižníc môžu používateľom umožniť prispôsobiť správanie odovzdávaním uzáverov ako argumentov dôležitých funkcií. Napríklad funkcia, ktorá triedi hodnoty, môže prijať argument uzáveru, ktorý porovnáva hodnoty, ktoré sa majú zoradiť podľa kritéria definovaného používateľom.
  • Keďže uzávery odkladajú vyhodnotenie, t. j. nič "nerobia", kým nie sú zavolané, môžu sa použiť na definovanie riadiacich štruktúr. Napríklad všetky štandardné riadiace štruktúry jazyka Smalltalk vrátane vetiev (if/then/else) a cyklov (while a for) sú definované pomocou objektov, ktorých metódy akceptujú uzávery. Používatelia môžu ľahko definovať aj vlastné riadiace štruktúry.
  • Možno vytvoriť viacero funkcií, ktoré sa uzavrú nad tým istým prostredím, čo im umožní súkromne komunikovať zmenou tohto prostredia (v jazykoch, ktoré umožňujú priradenie).

V schéme

(define foo #f) (define bar #f) (let ((secret-message "none")) (set! foo (lambda (msg) (set! secret-message msg))) (set! bar (lambda () secret-message))) (display (bar)) ; vypíše "none" (newline) (foo "meet me by the docks at the midnight") (display (bar)) ; vypíše "meet me by the docks at the midnight"
  • Uzávery možno použiť na implementáciu objektových systémov.

Poznámka: Niektorí používatelia nazývajú uzáverom akúkoľvek dátovú štruktúru, ktorá viaže lexikálne prostredie, ale tento termín sa zvyčajne vzťahuje konkrétne na funkcie.

Otázky a odpovede

Otázka: Čo je to uzávierka v informatike?

Odpoveď: Uzáver je funkcia, ktorá má svoje vlastné prostredie.

Otázka: Čo obsahuje prostredie uzáveru?

Odpoveď: Prostredie uzáveru obsahuje aspoň jednu viazanú premennú.

Otázka: Kto dal myšlienke uzáveru meno?

Odpoveď: Peter J. Landin dal myšlienke uzáveru meno v roku 1964.

Otázka: Ktorý programovací jazyk spopularizoval uzávery po roku 1975?

Odpoveď: Programovací jazyk Scheme spopularizoval uzávery po roku 1975.

Otázka: Sú anonymné funkcie a uzávery to isté?

Odpoveď: Anonymné funkcie sa niekedy nesprávne nazývajú uzávery, ale nie všetky anonymné funkcie sú uzávery.

Otázka: Čo robí z anonymnej funkcie uzáver?

Odpoveď: Anonymná funkcia je uzáver, ak má vlastné prostredie s aspoň jednou viazanou premennou.

Otázka: Je pomenovaná uzávierka anonymná?

Odpoveď: Nie, pomenovaná uzávierka nie je anonymná.

Súvisiace články

Autor

AlegsaOnline.com Uzáver v informatike: definícia, vlastnosti a význam

URL: https://sk.alegsaonline.com/art/21095

Zdieľať

Zdroje
  • developer.mozilla.org : "Core JavaScript Reference Objects:Array:Filter"
  • python.org : "Python Manual"
  • okmij.org : "Scheme example"