Datorzinātnē slēgums ir funkcija, kurai ir sava vide. Šajā vidē ir vismaz viens piesaistīts mainīgais (vārds, kam ir vērtība, piemēram, skaitlis). Slēguma vide saglabā piesaistītos mainīgos atmiņā starp slēguma lietošanas reizēm.
Pīters J. Landins 1964. gadā šai idejai deva nosaukumu "slēgšana". Scheme programmēšanas valoda pēc 1975. gada padarīja slēgšanu populāru. Daudzās programmēšanas valodās, kas radītas pēc šī laika, ir slēgumi.
Anonīmās funkcijas (funkcijas bez nosaukuma) dažkārt kļūdaini sauc par slēgumiem. Lielākajā daļā valodu, kurās ir anonīmās funkcijas, ir arī slēgšanas funkcijas. Arī anonīma funkcija ir slēgums, ja tai ir sava vide ar vismaz vienu piesaistītu mainīgo. Anonīma funkcija, kurai nav savas vides, nav slēgums. Nosaukta slēgšana nav anonīma.
Vienkārša definīcija un būtība
Vienkārši sakot, slēgums ir funkcija kopā ar to saistīto vidi. Kad funkcija tiek izveidota, tā „aiznes līdzi” atsauces uz mainīgajiem, kuri bija pieejami tās izveides laikā. Pat ja šī vide vairs nav pieejama lokālā izpildes kontekstā, slēgums saglabā piekļuvi šiem mainīgajiem, līdz slēgums vairs netiek izmantots un atkritumu savācējs tos iztīra.
Kā slēgums darbojas — piemēri
Zemāk ir vienkāršs piemērs JavaScript valodā, kas ilustrē skaitītāja slēgumu:
function makeCounter() { let count = 0; return function() { count += 1; return count; }; } const counter = makeCounter(); console.log(counter()); // 1 console.log(counter()); // 2 Šeit iekšējā funkcija ir slēgums: tā saglabā piekļuvi mainīgajam count, pat pēc tam, kad makeCounter izpilde ir beigusies.
Analogs piemērs Python (lambda vai iekšējā funkcija):
def make_counter(): count = 0 def inc(): nonlocal count count += 1 return count return inc c = make_counter() print(c()) # 1 print(c()) # 2 Leģiskā (lexical) vs dinamiskā skopēšana
Lielākā daļa mūsdienu valodu ar slēgumiem izmanto leksisko skopēšanu — mainīgo atsauces asociējas ar vietām koda struktūras laikā (kur funkcija tika definēta), nevis ar to, kur funkcija tiek izsaukta. Tas ļauj slēgumiem pārliecinoši „aiznest” kontekstu no definīcijas vietas. Dažas valodas vai izpildes vidi var izmantot dinamisku scoping, bet tas ir retāk sastopams un rada citāda veida uzvedību.
Implementācijas atslēgas
- Slēgums satur atsauci uz funkcionālo kodu un uz vidē esošajām saistībām (bindings).
- Atmiņas pārvaldība (garbage collection) parasti nodrošina, ka vide netiek atbrīvota, kamēr pastāv atsauce uz to no slēguma.
- Dažas valodas saglabā pilnu vides kopiju, citas — tikai atsauces uz nepieciešamajiem mainīgajiem; realizācija ietekmē veiktspēju un atmiņas patēriņu.
Pielietojumi
Slēgumi ir ļoti praktiski un tiek izmantoti daudzos kontekstos:
- Inkapsulācija un privātie dati: ļauj izveidot funkcijas vai objektus ar privātām mainīgajām, pieejamām tikai caur publiskajām metodēm.
- Fabrikas funkcijas: ģenerēt specializētas funkcijas ar iepriekš noteiktu konfigurāciju.
- Kallbacki un notikumu apstrāde: saglabāt stāvokli starp asinhroniem izsaukumiem.
- Daļēja piemērošana un karings: atgriezt jaunas funkcijas ar jau fiksētām dažām argumentu vērtībām.
- Iteratori un generatori: uzturēt iekšējo stāvokli starp seansiem.
Bieži sastopamas kļūdas un uzmanības punkti
- Neintuitīvas atsauces cilpās: valodās, kurās lokālie mainīgie cilpā tiek koplietoti (piemēram, JS ar
var), visas anonīmās funkcijas var saistīt vienu un to pašu mainīgo. Izmantojotletvai izveidojot atsevišķu slēgumu katrai iterācijai, šo problēmu var novērst. - Atmiņas noplūdes risks: ja slēgumi tur ilgi dzīvojošas atsauces uz lieliem datiem, var rasties nevēlama atmiņas izmantošana.
- Reassignācija: dažās valodās, lai mainītu ārējo mainīgo no iekšējās funkcijas, nepieciešams speciāls atslēgas vārds (piem., Python —
nonlocal,global).
Papildus piezīmes
Terminoloģija var dažkārt sajaukties: ne visas anonīmās funkcijas ir slēgumi — tās kļūst par slēgumiem tikai tad, ja tām ir piesaistīta vide. Tāpat, slēgums nav tikai funkcionāla programmēšanas īpašība — tas ir plaši izmantots paradigmu savienojums, kas ir pieejams daudzās imperatīvajās, objektorientētajās un funkcionālajās valodās.
Šī koncepcija ir fundamentāla mūsdienu programmēšanai: sapratne par to, kā slēgumi uztur stāvokli un kā tie ietekmē skopēšanu un dzīves ilgumu, palīdz rakstīt drošāku, modulārāku un vieglāk uzturamu kodu.