Ajout de l'enregistrement si la valeur de retour est Aucun
-
26-10-2019 - |
Question
Supposons qu'il y ait deux fonctions findUser(id:String):Option[User]
et findAddress(user:User):Option[Address]
invoquées comme suit:
for(user <- findUser(id); address <- findAddress(user)) println(address)
Maintenant, je voudrais ajouter la journalisation des erreurs à ce for-comprehension
. Je voudrais appeler une fonction log(msg:String)
si l'user
ou address
est introuvable.
for(user <- findUser(id) ifNone log("user not found"); address <- findAddress(user) ifNone log("address not found")) println(address)
Puis-je le faire sans changer les signatures de fonction?
La solution
Peut-être
implicit def withIfNone[A](o: Option[A]) = new {
def ifNone(action: => Unit) = { if (o == None) action; o }
}
Vous pouvez également envisager d'utiliser une ou l'autre au lieu de l'option (ou convertir vos options soit). Cela ne fonctionnerait pas avec un foreach (un pour sans rendement), mais vous pouvez faire
for(
a <- option1.toRight("option1 missing").right;
b <- option2.toRight("option2 missing").right)
yield f(a,b)
Ensuite, vous pouvez match de motif sur le résultat avec
case Left(error) => log (error)
case Right(result) => // use result
Autres conseils
Le Box
de Lift est une classe plus appropriée pour votre cas d'utilisation. Un Box
est comme un Option
, mais avec deux états vides: ok et erreur. Vous pouvez l'utiliser comme ceci:
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
}
Voir ce blog pour diverses suggestions liées à votre problème.
Il est peut-être un surpuissant, mais il semble un peu comme ce que tu voulais;)
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)
}
Si vous avez aucune idée de ce que vient de se passer de lire ce .