Say mam trzy funkcje dostępu do bazy danych foo
, bar
i baz
że każdy może powrócić Option[A]
gdzie A
jest jakiś wzór klasa, a połączenia są od siebie zależne.Unikanie głęboko zagnieżdżone kaskady opcję w Scala
Chciałbym wywołać funkcje sekwencyjnie iw każdym przypadku, zwrócić odpowiedni komunikat o błędzie, jeśli wartość nie zostanie znaleziona (None
).
Mój bieżący kod wygląda następująco:
Input is a URL: /x/:xID/y/:yID/z/:zID
foo(xID) match {
case None => Left(s"$xID is not a valid id")
case Some(x) =>
bar(yID) match {
case None => Left(s"$yID is not a valid id")
case Some(y) =>
baz(zID) match {
case None => Left(s"$zID is not a valid id")
case Some(z) => Right(process(x, y, z))
}
}
}
Jak widać, kod jest źle zagnieżdżone.
Jeśli zamiast tego używam for
ze zrozumieniem, nie mogę podać konkretne komunikaty o błędach, bo nie wiem, który to etap nie powiodło się:
(for {
x <- foo(xID)
y <- bar(yID)
z <- baz(zID)
} yield {
Right(process(x, y, z))
}).getOrElse(Left("One of the IDs was invalid, but we do not know which one"))
Jeśli używam map
i getOrElse
, ja skończyć z kodem prawie jak zagnieżdżony jako pierwszy przykład.
Czy jest to lepszy sposób ułożenia struktury, aby uniknąć zagnieżdżenia, zezwalając na określone komunikaty o błędach?
I złożył bilet byłaby kod powrotu 'Either', ale nie miałem czasu, aby nad nim pracować. Mamy wiele takich przypadków. – Ralph
@Ralph Oba też by działały. Lubię "Try", ponieważ mówi "Sukces" i "Niepowodzenie". Użycie polecenia "Spróbuj" nie oznacza, że musisz rzucić wyjątek, ale możesz mieć wyjątek alokujący nieprzydzielony stos, który nie spowalnia procesu. – wheaties
@wheaties - Trochę niebezpiecznie jest mieć niepotrzebne wyjątki, ponieważ jeśli zostaną rzucone, nie masz pojęcia, skąd pochodzą. Lepiej, jeśli to możliwe, przynajmniej użyć wzoru pożyczki podczas pracy z nimi, np. 'getAStacklessException (params) {e => ???/* Nie przechowuj w dowolnym miejscu ani nie korzystaj z kontraktów terminowych! * /} '. –