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?

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top