Desugaring for
map i flatMap
Desugaring for to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 1 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 for-comprehension?
Wyrażenie for-comprehension w Scali to specjalna składnia do pracy z kolekcjami i innymi typami kontenerowymi. Wygląda jak imperatywna pętla, ale w rzeczywistości jest cukrem składniowym, który kompilator przepisuje na wywołania map, flatMap, filter i foreach.
Zrozumienie procesu desugaringu pomaga analizować dowolne wyrażenie for-comprehension, także działające na własnych typach.
object Main {
def main(args: Array[String]): Unit = {
val result = for (x <- List(1, 2, 3)) yield x * 10
println(result)
}
}Pojedynczy generator staje się map
Gdy wyrażenie for-comprehension zawiera dokładnie jeden generator i używa yield, kompilator przepisuje je na pojedyncze wywołanie map.
for (x <- xs) yield f(x)- staje się
xs.map(x => f(x))
object Main {
def main(args: Array[String]): Unit = {
val a = for (x <- List(1, 2, 3)) yield x + 1
val b = List(1, 2, 3).map(x => x + 1)
println(a == b)
}
}Słowo kluczowe yield
Słowo kluczowe yield informuje Scalę, aby zebrała wyniki do nowej kolekcji tego samego rodzaju.
Bez yield wyrażenie for-comprehension wykonuje efekt uboczny dla każdego elementu i zwraca Unit (staje się wywołaniem foreach).
object Main {
def main(args: Array[String]): Unit = {
// No yield: side effect only
for (x <- List("a", "b")) println(x)
// With yield: builds a new List
val upper = for (x <- List("a", "b")) yield x.toUpperCase
println(upper)
}
}Dwa generatory stają się flatMap + map
W przypadku dwóch lub większej liczby generatorów zewnętrzne stają się wywołaniami flatMap, a najbardziej wewnętrzny staje się wywołaniem map.
for (x <- xs; y <- ys) yield f(x, y)- staje się
xs.flatMap(x => ys.map(y => f(x, y)))
object Main {
def main(args: Array[String]): Unit = {
val pairs = for {
x <- List(1, 2)
y <- List("a", "b")
} yield (x, y)
println(pairs)
}
}Równoważne wywołanie flatMap
W tym miejscu zapisujemy tę samą logikę na oba sposoby. Wykazanie ich równoważności dowodzi, że wyrażenia for-comprehension nie dodają żadnej magii, a jedynie poprawiają czytelność.
object Main {
def main(args: Array[String]): Unit = {
val sugar = for {
x <- List(1, 2)
y <- List(10, 20)
} yield x + y
val desugared = List(1, 2).flatMap(x => List(10, 20).map(y => x + y))
println(sugar)
println(sugar == desugared)
}
}Dlaczego dla zewnętrznego generatora używa się flatMap
Każdy element zewnętrzny tworzy całą kolekcję wyników wewnętrznych. Gdyby dla zewnętrznego generatora użyć map, otrzymalibyśmy zagnieżdżoną kolekcję, taką jak List(List(...), List(...)).
flatMap spłaszcza te zagnieżdżone listy do jednego płaskiego wyniku.
object Main {
def main(args: Array[String]): Unit = {
val nested = List(1, 2).map(x => List(10, 20).map(y => x + y))
val flat = List(1, 2).flatMap(x => List(10, 20).map(y => x + y))
println(nested)
println(flat)
}
}for bez yield to foreach
Pętla for bez yield jest przepisywana na foreach. Wykonuje treść pętli ze względu na efekty uboczne i zwraca Unit.
for (x <- xs) doSomething(x)- staje się
xs.foreach(x => doSomething(x))
object Main {
def main(args: Array[String]): Unit = {
val r: Unit = for (x <- List(1, 2, 3)) print(x + " ")
println()
println("Return type is Unit")
}
}Typ wyniku wynika z pierwszego generatora
Typ wyniku jest określany przez kolekcję pierwszego generatora. Wyrażenie for dla List zwraca List, dla Set — Set, a dla Option — Option.
object Main {
def main(args: Array[String]): Unit = {
val fromList = for (x <- List(1, 2, 2, 3)) yield x
val fromSet = for (x <- Set(1, 2, 2, 3)) yield x
println(fromList)
println(fromSet)
}
}Wiązanie wartości za pomocą =
Wewnątrz wyrażenia for-comprehension można wiązać wartości pośrednie za pomocą =. Pozwala to uniknąć ponownych obliczeń i poprawia czytelność.
Jest to przekształcane na wywołanie map, które przenosi dodatkową wartość w krotce.
object Main {
def main(args: Array[String]): Unit = {
val result = for {
x <- List(1, 2, 3)
doubled = x * 2
} yield doubled + 1
println(result)
}
}Działa z każdym typem mającym map/flatMap
Ponieważ desugaring opiera się wyłącznie na map i flatMap, wyrażenia for-comprehension działają z dowolnym typem, który definiuje te metody: Option, Either, Try, Future oraz własnymi klasami.
object Main {
def main(args: Array[String]): Unit = {
val combined = for {
a <- Some(2)
b <- Some(3)
} yield a * b
println(combined)
}
}Najważniejsza jest czytelność
Proszę porównać głęboko zagnieżdżony łańcuch flatMap/map z przejrzystym wyrażeniem for-comprehension. Kompilują się do tego samego, ale wersja for jest czytelna od góry do dołu niczym przepis.
object Main {
def main(args: Array[String]): Unit = {
val chained = List(1, 2).flatMap(a => List(3, 4).map(b => a * b))
val readable = for {
a <- List(1, 2)
b <- List(3, 4)
} yield a * b
println(chained == readable)
}
}Szybkie sprawdzenie
Jak kompilator wykonuje desugaring wyrażenia for-comprehension z dwoma generatorami i yield?
Podsumowanie
Nauczyli się Państwo, jak wygląda desugaring wyrażeń for-comprehension:
- Jeden generator +
yield→map - Wiele generatorów +
yield→flatMap(zewnętrzne) +map(wewnętrzne) - Brak
yield→foreachzwracająceUnit - Wiązania
val =dodają wartości pośrednie - Typ wyniku wynika z pierwszego generatora
Każdy typ mający map i flatMap może być używany w wyrażeniu for-comprehension.
Często zadawane pytania
Czy lekcja „Desugaring for” jest bezpłatna?
Tak — pełny tekst „Desugaring for” 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 „Desugaring for”?
map i flatMap Ć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 1 z 4.
Ile czasu zajmuje lekcja „Desugaring for”?
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.