Frage

Option Monade ist eine große expressive Art und Weise mit etwas oder nichts Dingen in Scala zu beschäftigen. Was aber, wenn man braucht eine Nachricht zu protokollieren, wenn „nichts“ auftritt? Gemäß der Scala-API-Dokumentation,

  

Der Typ Entweder wird oft als eine verwendet   Alternative zu scala.Option wo Links   darstellt Versagen (durch Konvention) und   Rechts ist ähnlich Einige.

Allerdings hatte ich kein Glück Best Practices entweder mit oder gute Praxisbeispiele, die entweder für die Verarbeitung von Fehlern zu finden. Schließlich habe ich mit dem folgenden Code für mein eigenes Projekt kommen:

    def logs: Array[String] = {
        def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
            val config = ca.getConfiguration(PID, null)
            config.properties getOrElse immutable.Map.empty
        }
        def checkType(any: Any): Option[Array[String]] = any match {
            case a: Array[String] => Some(a)
            case _ => None
        }
        def lookup: Either[(Symbol, String), Array[String]] =
            for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
                 val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
                 val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
            yield array

        lookup.fold(failure => { failure match {
            case ('warning, msg) => log(LogService.WARNING, msg)
            case ('debug, msg) =>   log(LogService.DEBUG, msg)
            case _ =>
        }; new Array[String](0) }, success => success)
    }

(Bitte beachten Sie, das ein Ausschnitt aus einem realen Projekt ist, so dass es nicht von selbst zusammenstellen wird)

Ich würde dankbar sein, zu wissen, wie Sie Either in Ihrem Code und / oder bessere Ideen auf Refactoring den obigen Code verwenden.

War es hilfreich?

Lösung

ist entweder verwendet, um eine der möglichen zwei aussagekräftige Ergebnisse zurückzukehren, anders als Option, die verwendet wird, ein einziges sinnvolles Ergebnis oder nichts zurück.

Ein einfaches Beispiel zu verstehen, ist unten angegeben (in Umlauf auf der Scala-Mailingliste eine Weile zurück):

def throwableToLeft[T](block: => T): Either[java.lang.Throwable, T] =
  try {
    Right(block)
  } catch {
    case ex => Left(ex)
  }

Da die Funktion Name schon sagt, wenn die Ausführung von „Block“ erfolgreich ist, wird es zurückgeben „Right ()“. Andernfalls, wenn ein Throwable ausgelöst wird, wird er zurückkehren "Left ()". Verwenden Mustervergleich das Ergebnis zu verarbeiten:

var s = "hello"
throwableToLeft { s.toUpperCase } match {
  case Right(s) => println(s)
  case Left(e) => e.printStackTrace
}
// prints "HELLO"

s = null
throwableToLeft { s.toUpperCase } match {
  case Right(s) => println(s)
  case Left(e) => e.printStackTrace
}
// prints NullPointerException stack trace

Ich hoffe, das hilft.

Andere Tipps

Scalaz Bibliothek hat etwas gleich Entweder Validation genannt. Es ist mehr als idiomatisches Entweder für den Einsatz als „bekommen entweder ein gültiges Ergebnis oder einen Fehler“.

Validierung ermöglicht es auch zu akkumulieren Fehler.

Edit: "gleich" Entweder ist complettly falsch, weil Validation ein applicative Funktor ist, und scalaz Entweder, mit dem Namen \ / (ausgesprochen "disjonction" oder "entweder"), ist eine Monade. Die Tatsache, dass Validierung kann Fehler accumalate ist wegen dieser Natur. Auf der anderen Seite, / hat einen „Anschlag früh“ Natur, an den ersten Stopp - \ / (lesen sie „links“ oder „Fehler“) es trifft. Es ist eine perfekte Erklärung hier: http://typelevel.org/blog /2014/02/21/error-handling.html

Siehe auch: http: / /scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html

Wie der Kommentar angefordert, Kopieren / Einfügen von dem obigen Link (einige Zeilen entfernt):

// Extracting success or failure values
val s: Validation[String, Int] = 1.success
val f: Validation[String, Int] = "error".fail

// It is recommended to use fold rather than pattern matching:
val result: String = s.fold(e => "got error: " + e, s => "got success: " + s.toString)

s match {
  case Success(a) => "success"
  case Failure(e) => "fail"
}

// Validation is a Monad, and can be used in for comprehensions.
val k1 = for {
  i <- s
  j <- s
} yield i + j
k1.toOption assert_≟ Some(2)

// The first failing sub-computation fails the entire computation.
val k2 = for {
  i <- f
  j <- f
} yield i + j
k2.fail.toOption assert_≟ Some("error")

// Validation is also an Applicative Functor, if the type of the error side of the validation is a Semigroup.
// A number of computations are tried. If the all success, a function can combine them into a Success. If any
// of them fails, the individual errors are accumulated.

// Use the NonEmptyList semigroup to accumulate errors using the Validation Applicative Functor.
val k4 = (fNel <**> fNel){ _ + _ }
k4.fail.toOption assert_≟ some(nel1("error", "error"))

Das Snippet Sie auf dem Laufenden scheint sehr gekünstelt. Sie verwenden entweder in einer Situation, in:

  1. Es ist nicht genug wissen, nur die Daten nicht verfügbar sind.
  2. Sie müssen eine von zwei unterschiedlichen Typen zurückzukehren.

eine Ausnahme in eine Linksdrehung ist in der Tat ein gemeinsamer Anwendungsfall. Über try / catch, hat es den Vorteil, dass der Code zusammen zu halten, was Sinn macht, wenn die Ausnahme ist ein erwartetes Ergebnis . Die gängigste Methode Entweder ist die Handhabung Mustervergleich:

result match {
  case Right(res) => ...
  case Left(res) => ...
}

Eine weitere interessante Art und Weise Either der Handhabung ist, wenn es in einer Sammlung erscheint. Wenn eine Karte über eine Sammlung zu tun, könnte eine Ausnahme werfen nicht lebensfähig sein, und Sie können einige andere Informationen als „nicht möglich“ zurückkehren möchten. Entweder mit Hilfe ermöglicht Ihnen, das zu tun, ohne den Algorithmus zu überlasten:

val list = (
  library 
  \\ "books" 
  map (book => 
    if (book \ "author" isEmpty) 
      Left(book) 
    else 
      Right((book \ "author" toList) map (_ text))
  )
)

Hier erhalten wir eine Liste aller Autoren in der Bibliothek, und eine Liste der Bücher, ohne Autor. So können wir dann weiter zu verarbeiten entsprechend:

val authorCount = (
  (Map[String,Int]() /: (list filter (_ isRight) map (_.right.get))) 
   ((map, author) => map + (author -> (map.getOrElse(author, 0) + 1)))
  toList
)
val problemBooks = list flatMap (_.left.toSeq) // thanks to Azarov for this variation

Also, Grund Entweder Nutzung geht so. Es ist nicht eine besonders nützliche Klasse, aber wenn es Sie es hätte zuvor gesehen. Auf der anderen Seite ist es nicht unnütz auch nicht.

Katzen haben eine schöne Möglichkeit, ein Entweder von Ausnahme-Wurf-Code zu erstellen:

val either: Either[NumberFormatException, Int] =
  Either.catchOnly[NumberFormatException]("abc".toInt)
// either: Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "abc")

in https : //typelevel.org/cats/datatypes/either.html#working-with-exception-y-code

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