Sulgemine (informaatika) — funktsioon koos oma keskkonnaga (closure)

Õpi sulgemisi (closure) — funktsioonid, mis hoiavad oma keskkonna ja seotud muutujaid mälus; selgitatud tööpõhimõte, näited ja kasutus programmeerimises.

Autor: Leandro Alegsa

Arvutiteaduses on sulgemine funktsioon, millel on oma keskkond. Selline keskkond sisaldab vähemalt üht seotud muutujat — nime, millel on väärtus (näiteks arv või osuti). Sulgemine „seob“ selle funktsiooni juurde need muutujad ja hoiab neid mälus ka pärast seda, kui funktsiooni deklareerinud kontekst on lõppenud; see võimaldab funktsioonil kasutada ja muuta neid muutujaid hilisemal ajal.

Peter J. Landin andis sellele ideele 1964. aastal nime closure. Programmeerimiskeel Scheme tegi sulgemised populaarseks pärast 1975. aastat. Alates sellest ajast on sulgemiste tugi levinud paljudes programmeerimiskeeltes (näiteks JavaScript, Python, Ruby, Lisp-pere keeled ja teised), kus need pakuvad võimsaid abstraktsioone ja puhast viisi oleku kapseldamiseks.

Kuidas sulgemised töötavad

Sulgemine tekib siis, kui funktsioon (sisefunktsioon) viitab muutujatele, mis on defineeritud väliskontekstis (välisfunktsioonis). Kui välisfunktsioon lõpetab töö ja tagastab sisefunktsiooni, jääb selle sisefunktsiooni juurde alles viide väliskonteksti seotud muutujatele — see komplekt seotud muutujatest moodustabgi sulgemise keskkonna.

Lihtne illustratsioon (loogiline kirjeldus):
- välistesamm: defineeri funktsioon A, mis loob muutuja x ja defineerib funktsiooni B, mis kasutab x;
- tagastus: A tagastab funktsiooni B;
- jätkamine: isegi pärast A lõpetamist säilitab B juurdepääsu muutuja x väärtusele tänu sulgemisele.

Kus sulgemisi kasutatakse

  • Püsiva oleku loomine ja andmete kapseldamine (privaatsete muutujate loomine ilma klassita).
  • Tagasikutsed (callbacks) ja sündmusekäsitlejad, kus funktsioon peab säilitama konteksti hilisemateks väljakutseteks.
  • Funktsionaalne programmeerimine — osaliselt rakendamine (partial application), currying ja kõrgema järgu funktsioonid kasutavad sageli sulgemisi.
  • Anname funktsioonile juurdepääsu sisemisele konfiguratsioonile ilma globaalseid muutujad kasutamata.

Mälu ja eluiga

Kuna sulgemine hoiab omas keskkonnas muutujaid mälus, tuleb olla tähelepanelik mälu kasutamise suhtes. Tänapäevased prügikoristajad (garbage collectors) vabastavad mälu, kui sulgemisi ei viitata enam kuskilt. Kuid pikaealised või palju mälu hõlmavad sulgemised võivad kaasa tuua ootamatu mälu tarbimise, kui neid hoitakse ringkäidavas struktuuris või globaalsete registrite kaudu.

Märkus anonüümsete funktsioonide kohta

Anonüümseid funktsioone (funktsioone, millel pole nime) nimetatakse mõnikord ekslikult sulgemisteks. Enamikus keeltes, kus on anonüümsed funktsioonid, on ka sulgemised, kuid need kaks mõistet ei ole identsed: anonüümne funktsioon on sulgemine ainult siis, kui tal on oma keskkond, millel on vähemalt üks seotud muutuja. Anonüümne funktsioon, millel puudub oma keskkond, ei ole sulgemine. Samuti võib sulgemine olla nimega — nimeline sulgemine ei ole anonüümne.

Lisaks on oluline eristada leksikaalset (staatilist) ja dünaamilist scopingut: enamik tänapäevaseid sulgemisi põhinevad leksikaalsel scopingul, kus seotud muutujate sidumine toimub definitsiooni ajal, mitte funktsiooni käivituse ajal.

Kui soovite, võin lisada lühikese näite konkreetse programmeerimiskeelega (nt JavaScript või Python), et sulgemiste tööd koodi näitel illustreerida.

Sulgemine ja esimese klassi funktsioonid

Väärtused võivad olla numbrid või muud liiki andmed, näiteks tähed, või lihtsamatest osadest koosnevad andmestruktuurid. Programmeerimiskeele reeglites on esimese klassi väärtused väärtused, mida saab funktsioonidele anda, funktsioone tagastada ja muutuja nimega siduda. Funktsioone, mis võtavad või tagastavad teisi funktsioone, nimetatakse kõrgema klassi funktsioonideks. Enamikus keeltes, kus funktsioonid on esimese klassi väärtused, on ka kõrgema astme funktsioonid ja sulgemised.

Vaadake näiteks järgmist Scheme funktsiooni:

; Tagastage nimekiri kõigist raamatutest, mille eksemplare on müüdud vähemalt KOLMAPÄEVA jooksul. (define (best-selling-books threshold) (filter (lambda (book) (>= (book-sales book) threshold)) book-list))

Selles näites on lambda-väljend (lambda (raamat) (>= (raamat-müük raamat) lävend))) osa funktsioonist best-selling-books. Funktsiooni käivitamisel peab Scheme tegema lambda väärtuse. Ta teeb seda, tehes sulgemise lambda koodiga ja viitega muutujale threshold, mis on vaba muutuja lambda sees. (Vaba muutuja on nimi, mis ei ole seotud väärtusega).

Seejärel teostab filtri funktsioon sulgemise iga raamatu kohta nimekirjas, et valida, milliseid raamatuid tagastada. Kuna sulgemisfunktsioonil endal on viide lävendile, saab sulgemisfunktsioon seda väärtust kasutada iga kord, kui filter käivitab sulgemisfunktsiooni. Funktsiooni filter ise võib kirjutada täiesti eraldi faili.

Siin on sama näide ümber kirjutatud ECMAScriptis (JavaScript), mis on teine populaarne keel, mis toetab sulgemisi:

// Tagastab nimekirja kõigist raamatutest, mille müüdud eksemplaride arv on vähemalt 'threshold'. function bestSellingBooks(threshold) { return bookList. filter( function(book) { return book. sales >= threshold; }     ); }

ECMAScript kasutab siin lambda asemel sõna function ja meetodit Array.filter funktsiooni filter asemel, kuid muidu teeb kood sama asja samamoodi.

Funktsioon võib luua sulgemise ja tagastada selle. Järgmine näide on funktsioon, mis tagastab funktsiooni.

Süsteemis:

; Tagastab funktsiooni, mis lähendab f ; tuletist, kasutades dx intervalli, mis peaks olema sobivalt väike. (define (derivative f dx) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx))))

ECMAScriptis:

// Tagastame funktsiooni, mis lähendab f // tuletatud väärtust, kasutades intervalli dx, mis peaks olema sobivalt väike. function derivative(f, dx) { return function(x) { return (f(x + dx) - f(x)) / dx; }; }; }

Sulgemiskeskkond säilitab seotud muutujad f ja dx pärast ümbritseva funktsiooni (tuletis) tagasipöördumist. Keeltes, kus ei ole sulgemiskeskkonda, läheksid need väärtused pärast ümbritseva funktsiooni tagasipöördumist kaduma. Keeltes, kus on sulgemiskeskkonnad, peab seotud muutuja jääma mällu nii kaua, kui mõni sulgemiskeskkond seda omab.

Sulgemine ei pea olema moodustatud anonüümse funktsiooni abil. Näiteks Pythoni programmeerimiskeelel on piiratud toetus anonüümsete funktsioonide jaoks, kuid seal on olemas sulgemised. Näiteks võib eespool toodud ECMAScript'i näidet Pythonis rakendada järgmiselt:

# Tagastab funktsiooni, mis lähendab f # tuletatud väärtust kasutades intervalli dx, mis peaks olema sobivalt väike. def derivative(f, dx): def gradient(x): return (f(x + dx) - f(x)) / dx return gradient

Selles näites moodustab funktsioon nimega gradient koos muutujatega f ja dx sulgemise. Välimine ümbritsev funktsioon nimega derivatiiv tagastab selle sulgemise. Sellisel juhul toimiks ka anonüümne funktsioon.

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

Python peab sageli kasutama selle asemel nimelisi funktsioone, sest selle lambda-avaldused võivad sisaldada ainult teisi avaldusi (kood, mis tagastab väärtuse), mitte avaldusi (kood, millel on mõju, kuid ei ole väärtust). Kuid teistes keeltes, näiteks Scheme'is, tagastab kogu kood väärtuse; Scheme'is on kõik väljend.

Sulgemiste kasutamine

Sulgemisi kasutatakse mitmel otstarbel:

  • Tarkvararaamatukogude projekteerijad saavad võimaldada kasutajatel kohandada käitumist, andes olulistele funktsioonidele argumentidena üle sulgemisi. Näiteks funktsioon, mis sorteerib väärtusi, võib vastu võtta sulgemisargumendi, mis võrdleb sorteeritavaid väärtusi vastavalt kasutaja määratud kriteeriumile.
  • Kuna sulgemised lükkavad hindamise edasi - st nad ei "tee" midagi enne, kui neid kutsutakse - saab neid kasutada juhtimisstruktuuride defineerimiseks. Näiteks kõik Smalltalki standardsed juhtimisstruktuurid, sealhulgas hargnemised (if/then/else) ja tsüklid (while ja for), on defineeritud objektide abil, mille meetodid aktsepteerivad sulgemisi. Kasutajad saavad hõlpsasti defineerida ka omaenda juhtimisstruktuure.
  • Saab luua mitu funktsiooni, mis sulguvad sama keskkonna üle, võimaldades neil suhelda eraviisiliselt, muutes seda keskkonda (keeltes, mis lubavad määramist).

Süsteemis

(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)) ; prindib "none" (newline) (foo "meet me by the docks at midnight") (display (bar)) ; prindib "meet me by the docks at midnight"
  • Sulgemisi saab kasutada objektisüsteemide rakendamiseks.

Märkus: Mõned kõnelejad nimetavad mis tahes andmestruktuuri, mis seob leksikaalset keskkonda, sulgemiseks, kuid tavaliselt viitab see termin konkreetselt funktsioonidele.

Küsimused ja vastused

K: Mis on sulgemine arvutiteaduses?


V: Sulgemine on funktsioon, millel on oma keskkond.

K: Mida sisaldab sulgemise keskkond?


V: Sulgemise keskkond sisaldab vähemalt ühte seotud muutujat.

K: Kes andis closure'ile nime?


V: Peter J. Landin andis closure'ile nime 1964. aastal.

K: Milline programmeerimiskeel tegi sulgemised populaarseks pärast 1975. aastat?


V: Programmeerimiskeel Scheme tegi sulgemised populaarseks pärast 1975. aastat.

K: Kas anonüümsed funktsioonid ja sulgemised on sama asi?


V: Anonüümseid funktsioone nimetatakse mõnikord ekslikult sulgemisteks, kuid kõik anonüümsed funktsioonid ei ole sulgemised.

K: Mis teeb anonüümsest funktsioonist sulgemise?


V: Anonüümne funktsioon on sulgemine, kui tal on oma keskkond, millel on vähemalt üks seotud muutuja.

K: Kas nimeline sulgemine on anonüümne?


V: Ei, nimeline sulgemine ei ole anonüümne.


Otsige
AlegsaOnline.com - 2020 / 2025 - License CC3