Domknięcia
Przechwytywanie stanu
Domknięcia to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Czym jest domknięcie?
Domknięcie to funkcja, która przechwytuje zmienne z otaczającego zakresu, w którym została zdefiniowana. „Domyka” te zmienne, zachowując do nich dostęp nawet po zakończeniu działania tego zakresu.
object Main {
def main(args: Array[String]): Unit = {
val factor = 3
val multiply = (x: Int) => x * factor
println(multiply(5))
}
}Przechwytywanie zmiennej wolnej
W wyrażeniu x => x * factor x jest parametrem, natomiast factor to zmienna wolna pobrana z otaczającego zakresu. Funkcja przechowuje do niej odwołanie.
object Main {
def main(args: Array[String]): Unit = {
val greeting = "Hello"
val greet = (name: String) => s"$greeting, $name!"
println(greet("Ann"))
println(greet("Bob"))
}
}Domknięcia żyją dłużej niż ich zakres
Gdy funkcja zwraca domknięcie, przechwycone zmienne pozostają aktywne tak długo, jak długo istnieje domknięcie, nawet jeśli funkcja, która je zdefiniowała, już zakończyła działanie.
object Main {
def makeAdder(n: Int): Int => Int = x => x + n
def main(args: Array[String]): Unit = {
val add10 = makeAdder(10)
val add100 = makeAdder(100)
println(add10(5))
println(add100(5))
}
}Każde domknięcie ma własne przechwycone wartości
Dwukrotne wywołanie fabryki funkcji tworzy dwa niezależne domknięcia, z których każde pamięta własną przechwyconą wartość.
object Main {
def prefixer(p: String): String => String = s => p + s
def main(args: Array[String]): Unit = {
val withDr = prefixer("Dr. ")
val withMr = prefixer("Mr. ")
println(withDr("Smith"))
println(withMr("Jones"))
}
}Przechwytywanie zmiennego stanu
Domknięcie może przechwycić zmienną var, a następnie zarówno ją odczytywać, jak i aktualizować. Dzięki temu może zachowywać stan między wywołaniami, na przykład działać jak licznik.
object Main {
def main(args: Array[String]): Unit = {
var count = 0
val increment = () => { count += 1; count }
println(increment())
println(increment())
println(increment())
}
}Fabryka liczników
Połączmy te idee: funkcja zwracająca domknięcie, które przechwytuje własną prywatną zmienną var, daje niezależny, hermetyczny licznik.
object Main {
def counter(): () => Int = {
var n = 0
() => { n += 1; n }
}
def main(args: Array[String]): Unit = {
val c1 = counter()
val c2 = counter()
println(c1())
println(c1())
println(c2())
}
}Domknięcia przechwytują odwołania, nie kopie
Domknięcie przechwytuje zmienną, a nie jej migawkę. Jeśli przechwycona zmienna var zmieni się po utworzeniu domknięcia, domknięcie zobaczy nową wartość.
object Main {
def main(args: Array[String]): Unit = {
var msg = "first"
val show = () => println(msg)
show()
msg = "second"
show()
}
}Preferowanie przechwytywania val
Przechwytywanie niezmiennej wartości val pozwala uniknąć niespodzianek: przechwycona wartość nigdy się nie zmienia, więc domknięcie działa w przewidywalny sposób. W kodzie funkcyjnym warto preferować przechwytywanie val.
object Main {
def main(args: Array[String]): Unit = {
val taxRate = 0.2
val withTax = (price: Double) => price * (1 + taxRate)
println(withTax(100))
}
}Domknięcia i metody kolekcji
Lambdy przekazywane do map, filter itp. są domknięciami, gdy odwołują się do zmiennych zewnętrznych. To niezwykle częsty przypadek w codziennym programowaniu w Scali.
object Main {
def main(args: Array[String]): Unit = {
val threshold = 3
val nums = List(1, 2, 3, 4, 5)
val big = nums.filter(_ > threshold)
println(big)
}
}Pułapka przechwytywania w pętlach
W Scali zmienna pętli for jest nowym powiązaniem w każdej iteracji, więc domknięcia przechwytują różne wartości. Pozwala to uniknąć klasycznego błędu spotykanego w niektórych innych językach.
object Main {
def main(args: Array[String]): Unit = {
val fns = for (i <- 1 to 3) yield () => i
println(fns.map(f => f()))
}
}Domknięcia hermetyzują zachowanie i dane
Domknięcie łączy zachowanie (ciało funkcji) z danymi (przechwyconymi zmiennymi). Jest lekką alternatywą dla małego obiektu z jedną metodą.
object Main {
def discounter(rate: Double): Double => Double = price => price * (1 - rate)
def main(args: Array[String]): Unit = {
val sale = discounter(0.25)
println(sale(80))
println(sale(200))
}
}Szybkie sprawdzenie
Co domknięcie przechwytuje z otaczającego zakresu?
Podsumowanie
Omówiono domknięcia:
- Domknięcie przechwytuje zmienne wolne z otaczającego zakresu
- Przechwycone zmienne żyją dłużej niż funkcja, która je zdefiniowała
- Każda instancja domknięcia ma własny przechwycony stan
- Domknięcia przechwytują odwołania, więc przechwycone zmienne mogą się zmieniać
- Lambda przekazywana do
map/filterto codzienny przykład domknięcia
Często zadawane pytania
Czy lekcja „Domknięcia” jest bezpłatna?
Tak — pełny tekst „Domknięcia” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Co nauczysz się w „Domknięcia”?
Przechwytywanie stanu Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?
Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Domknięcia”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?
Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.