Scala for Backend Engineering & Functional Programming · Lekcja

Komponowanie Either

map i flatMap

Lekcja 3 z 413 kroki

Komponowanie Either to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 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.

Komponowanie obliczeń

Rzeczywiste programy łączą kilka etapów, które mogą zakończyć się niepowodzeniem: parsowanie, walidację, wyszukiwanie i obliczenia. Either pozwala komponować takie etapy, tak aby pierwsze niepowodzenie natychmiast kończyło cały łańcuch.

Służą do tego map, flatMap oraz konstrukcje for.

flatMap łączy wartości Either

flatMap stosuje funkcję, która sama zwraca Either. Jeśli odbiorcą jest Left, funkcja nie zostaje wywołana, a Left jest propagowane dalej.

object Main {
  def positive(n: Int): Either[String, Int] =
    if (n > 0) Right(n) else Left("not positive")

  def main(args: Array[String]): Unit = {
    val r = Right(5).flatMap(positive)
    val l = Right(-1).flatMap(positive)
    println(r)
    println(l)
  }
}

Przerywanie przy błędzie

Gdy łączą Państwo wiele wywołań flatMap, pierwsze Left zatrzymuje całe przetwarzanie. Późniejsze etapy są pomijane, a ten błąd staje się wynikiem końcowym.

object Main {
  def step(label: String, n: Int): Either[String, Int] = {
    println(s"running $label")
    Right(n + 1)
  }

  def main(args: Array[String]): Unit = {
    val result = Left("early error").asInstanceOf[Either[String, Int]]
      .flatMap(n => step("A", n))
      .flatMap(n => step("B", n))
    println(result)
  }
}

Konstrukcja for dla Either

Ponieważ Either działa prawostronnie, można używać go w konstrukcji for. Każdy operator <- rozpakowuje wartość Right; dowolny Left zatrzymuje konstrukcję i staje się jej wynikiem.

object Main {
  def parse(s: String): Either[String, Int] =
    s.toIntOption.toRight(s"bad: $s")

  def main(args: Array[String]): Unit = {
    val sum = for {
      a <- parse("3")
      b <- parse("4")
    } yield a + b
    println(sum)
  }
}

Nieudana konstrukcja for

Jeśli dowolny etap konstrukcji zwróci Left, całe wyrażenie przyjmuje tę wartość Left, a kolejne etapy nie są wykonywane.

object Main {
  def parse(s: String): Either[String, Int] =
    s.toIntOption.toRight(s"bad: $s")

  def main(args: Array[String]): Unit = {
    val sum = for {
      a <- parse("3")
      b <- parse("oops")
      c <- parse("5")
    } yield a + b + c
    println(sum)
  }
}

Łączenie walidacji

Realistyczny potok: sparsowanie ciągu znaków, sprawdzenie reguły biznesowej, a następnie przekształcenie. Każdy etap zwraca Either.

object Main {
  def parse(s: String): Either[String, Int] = s.toIntOption.toRight("not a number")
  def checkRange(n: Int): Either[String, Int] =
    if (n >= 1 && n <= 100) Right(n) else Left("out of range")

  def process(s: String): Either[String, Int] =
    parse(s).flatMap(checkRange).map(_ * 10)

  def main(args: Array[String]): Unit = {
    println(process("7"))
    println(process("500"))
    println(process("x"))
  }
}

map a flatMap

Należy użyć map, gdy funkcja zwraca zwykłą wartość. flatMap stosuje się, gdy zwraca kolejny obiekt Either, aby uniknąć zagnieżdżenia Either[String, Either[String, Int]].

@main def run(): Unit = {
  val withMap: Either[String, Int] = Right(2).map(_ + 1)
  val nested: Either[String, Either[String, Int]] = Right(2).map(n => Right(n + 1))
  val flat: Either[String, Int] = Right(2).flatMap(n => Right(n + 1))
  println(withMap)
  println(nested)
  println(flat)
}

Łączenie niezależnych wartości

Konstrukcja for działa również wtedy, gdy poszczególne etapy nie zależą od poprzedniego. Wszystkie muszą zakończyć się sukcesem, aby wykonała się końcowa instrukcja yield.

object Main {
  def parse(s: String): Either[String, Int] = s.toIntOption.toRight(s"bad: $s")

  def main(args: Array[String]): Unit = {
    val combined = for {
      x <- parse("10")
      y <- parse("20")
      z <- parse("30")
    } yield List(x, y, z).sum
    println(combined)
  }
}

Transformacja błędów w stylu leftMap

Standardowa biblioteka nie udostępnia dla Either metody leftMap, ale błąd można przekształcić za pomocą swap.map(...).swap lub przez mapowanie wewnątrz fold. Pozwala to zachować spójne typy błędów w całym potoku.

@main def run(): Unit = {
  val e: Either[String, Int] = Left("low-level error")
  val mapped = e.swap.map(msg => s"context: $msg").swap
  println(mapped)
}

Połączenie wszystkiego

Niewielki potok kalkulatora, który parsuje dwie liczby i wykonuje dzielenie, zgłaszając każde niepowodzenie jako typowany błąd.

object Main {
  def parse(s: String): Either[String, Int] = s.toIntOption.toRight(s"bad number: $s")
  def divide(a: Int, b: Int): Either[String, Int] =
    if (b == 0) Left("division by zero") else Right(a / b)

  def calc(x: String, y: String): Either[String, Int] =
    for {
      a <- parse(x)
      b <- parse(y)
      r <- divide(a, b)
    } yield r

  def main(args: Array[String]): Unit = {
    println(calc("20", "4"))
    println(calc("20", "0"))
    println(calc("x", "4"))
  }
}

Dlaczego to ma znaczenie

Komponowanie Either daje programowanie zorientowane na tory: ścieżka sukcesu przebiega przez Right, a każdy błąd zbacza na tor Left i omija pozostałą część. Bez wyjątków, bez sprawdzania wartości null, tylko wartości.

Szybkie sprawdzenie

Sprawdźmy, czy rozumieją Państwo komponowanie Either.

Podsumowanie

Opanował(a) Pan/Pani komponowanie Either:

  • flatMap łączy etapy, które mogą zakończyć się niepowodzeniem, i przerywa działanie przy pierwszym Left.
  • Konstrukcje for ułatwiają czytelny zapis wieloetapowych potoków.
  • Należy używać map dla zwykłych wyników, a flatMap dla funkcji zwracających Either.
  • Błędy można przekształcać za pomocą swap.map(...).swap.
Bezpłatny start

Ucz się Scala dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
39
Lekcje
143

Często zadawane pytania

Czy lekcja „Komponowanie Either” jest bezpłatna?

Tak — pełny tekst „Komponowanie Either” 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 „Komponowanie Either”?

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 3 z 4.

Ile czasu zajmuje lekcja „Komponowanie Either”?

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.

Wszystkie lekcje w tym kursie

  1. Either do obsługi błędów
  2. Try, Success, Failure
  3. Komponowanie Either
  4. Konwersja między typami
← Powrót do Scala for Backend Engineering & Functional Programming