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?

Était-ce utile?

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 .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top