Fügen Sie Protokollierung hinzu, wenn der Rückgabewert keine ist
-
26-10-2019 - |
Frage
Angenommen, es gibt zwei Funktionen findUser(id:String):Option[User]
und findAddress(user:User):Option[Address]
wie folgt aufgerufen:
for(user <- findUser(id); address <- findAddress(user)) println(address)
Jetzt möchte ich ein Fehler hinzufügen, der sich dazu anmelden for-comprehension
. Ich möchte a anrufen log(msg:String)
Funktionieren Sie, wenn beides user
oder address
wurde nicht gefunden.
for(user <- findUser(id) ifNone log("user not found"); address <- findAddress(user) ifNone log("address not found")) println(address)
Kann ich es tun, ohne die Funktionssignaturen zu ändern?
Lösung
Vielleicht
implicit def withIfNone[A](o: Option[A]) = new {
def ifNone(action: => Unit) = { if (o == None) action; o }
}
Sie können auch in Betracht ziehen, entweder anstelle der Option zu verwenden (oder Ihre Optionen in entweder konvertieren). Das würde nicht mit einem foreach (a für ohne Ertrag) funktionieren, aber Sie könnten es tun
for(
a <- option1.toRight("option1 missing").right;
b <- option2.toRight("option2 missing").right)
yield f(a,b)
Dann können Sie die Übereinstimmung mit dem Ergebnis mit mustern
case Left(error) => log (error)
case Right(result) => // use result
Andere Tipps
Lift Box
ist eine angemessenere Klasse für Ihren Verwendungsfall. EIN Box
ist wie ein Option
, aber mit zwei leeren Zuständen: OK und Fehler. Sie könnten es so verwenden:
val addr = for {
user <- findUser(id) ?~ "user not found"
address <- findAddress(user) ?~ "address not found"
} yield address
address match {
case Full(addr) => println(addr)
case oops: Failure => println(oops.msg) // see Failure for more details
}
Sehen Dieser Blog für verschiedene Vorschläge im Zusammenhang mit Ihrem Problem.
Es mag ein Overkill sein, aber es sieht ziemlich ähnlich aus, was Sie wollten;)
object Extensions {
// You need a wrapper since Option is sealed
class OptionWrapper[E](option: Option[E]) {
def foreach[U](f: E => U) {
option foreach f
}
def isEmpty = option.isEmpty
}
// Modification trait for OptionWrapper
trait ErrorLogging[E] extends OptionWrapper[E] {
abstract override def foreach[U](f: E => U) {
if (isEmpty)
println("error")
else
super.foreach(f)
}
}
// Accessor for the new mixin
def log[E](option: Option[E]) = new OptionWrapper(option) with ErrorLogging[E]
}
object TestingLogger extends App {
case class User(address: String)
def findUser(id: Int): Option[User] = if (id == 1) Some(User("address")) else None
def findAddress(user: User): Option[String] = Some(user.address)
import Extensions._
for {
user <- log(findUser(1)) // prints out address
address <- log(findAddress(user))
} println(address)
for {
user <- log(findUser(2)) // prints out error
address <- log(findAddress(user))
} println(address)
}
Wenn Sie keine Ahnung haben, was gerade passiert ist gelesen Dies.