Pregunta

mónada Option es una gran manera expresiva que lidiar con algo o nada las cosas en la Scala. Pero lo que si hay que registrar un mensaje cuando se produce "nada"? De acuerdo con la documentación de la API Scala,

  

El tipo O se utiliza a menudo como una   alternativa a la izquierda, donde scala.Option   representa fallo (por convención) y   La derecha es similar a algunos.

Sin embargo, no tuve la suerte de encontrar las mejores prácticas, ya sea utilizando o buenos ejemplos del mundo real que sea por errores de procesamiento. Por último se me ha ocurrido con el siguiente código para mi propio proyecto:

    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)
    }

(Tenga en cuenta que este es un fragmento de un proyecto real, por lo que no se compilará en su propia)

Yo estaría agradecido de saber cómo está utilizando Either en su código y / o mejores ideas sobre refactorización el código de seguridad.

¿Fue útil?

Solución

O se utiliza para devolver uno de posibles dos resultados significativos, a diferencia de la opción que se utiliza para devolver un resultado significativo solo o nada.

Un ejemplo fácil de entender es la siguiente (distribuido en la Scala lista de correo hace un tiempo):

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

Como el nombre de la función implica, si la ejecución del "bloque" tiene éxito, volverá "Derecha ()". De lo contrario, si se lanza un Throwable, devolverá "Izquierda ()". Utilice la coincidencia de patrones para procesar el resultado:

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

Espero que ayude.

Otros consejos

biblioteca Scalaz tiene algo por igual cualquier llamado de validación. Es más idiomática que sea para su uso como "obtener ya sea un resultado válido o un fracaso".

validación también permite acumular errores.

Editar: "igual" O es complettly falsa, porque Validación es un funtor aplicativo, y scalaz O, llamado \ / (pronunciado "disjonction" o "cualquiera"), es una mónada. El hecho de que la validación puede accumalate errores se debe a que la naturaleza. Por otro lado, / tiene un carácter "parada temprana", parando en la primera - \ / (leerlo "izquierda", o "error") que encuentra. Hay una explicación perfecta aquí: http://typelevel.org/blog /2014/02/21/error-handling.html

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

A medida solicitada por el comentario, copiar / pegar el enlace anterior (algunas líneas eliminado):

// 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"))

El fragmento informados parece muy artificial. Se utiliza ya sea en una situación en la que:

  1. No es suficiente conocer sólo los datos no está disponible.
  2. Es necesario devolver uno de dos tipos distintos.

Volviendo una excepción en una izquierda es, de hecho, un caso de uso común. Con el try / catch, tiene la ventaja de mantener el código juntos, lo cual tiene sentido si la excepción es un resultado esperado . La forma más común de manejar cualquier es la coincidencia de patrones:

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

Otra forma interesante de manejo Either es cuando aparece en una colección. Al hacer un mapa sobre una colección, una excepción podría no ser viable, y es posible que desee volver alguna información que no sea "no es posible". El uso de un O le permite hacer lo que sin sobrecargar el algoritmo:

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

Aquí tenemos una lista de todos los autores en la biblioteca, más una lista de libros sin autor. A continuación podremos procesar más que en consecuencia:

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

Por lo tanto, cualquier uso básico va así. No es una clase particularmente útil, pero si lo fuera que hubiera visto antes. Por otro lado, no sirve de nada tampoco.

Los gatos tienen una buena manera de crear un código de excepción de cualquier lanzamiento de:

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

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top