2011-04-20 15 views
28

recientemente he visto así:código Scala captura de confusión

val maybeInt = catching(classOf[NFE]) opt arg.toInt 

¿Qué es este opt? ¿Una opción? ¿Por qué no usa getOrElse para extraer el valor? En el código anterior, ¿será maybeInt Ninguno si se lanza una NumberFormatException?

+0

¡Oye, ese código es familiar! :-) –

+0

Me lo imaginaba :) – Geo

Respuesta

34

catching Parece que es una especie de método de llamada, ¿no? Lo es, pero en realidad devuelve una instancia de una clase Catch; no toma directamente un argumento. Esta clase tiene dos métodos que son particularmente útiles para tratar con excepciones (y varios más para detectar múltiples excepciones). La primera es

def opt [U >: T] (body: ⇒ U) : Option[U] 

que está siendo utilizado aquí - le das algo que puede lanzar una excepción, y volverá Some(result) si todo ha ido bien, y si la excepción None objetivo fue capturado:

scala> type NFE = NumberFormatException 
defined type alias NFE 

scala> import scala.util.control.Exception._ 
import scala.util.control.Exception._ 

scala> catching(classOf[NFE]).opt("fish".toInt) 
res0: Option[Int] = None 

scala> catching(classOf[NFE]).opt("42".toInt) 
res1: Option[Int] = Some(42) 

A continuación, puede tratar esto con map o filter o getOrElse o cualquier otra cosa que use para tratar las opciones.

El otro método útil es either, que devuelve una instancia de Left(exception) si se produce una excepción, y una Right(result) si no fuera:

scala> catching(classOf[NFE]).either("fish".toInt) 
res2: Either[Throwable,Int] = Left(java.lang.NumberFormatException: For input string: "fish") 

scala> catching(classOf[NFE]).either("42".toInt) 
res3: Either[Throwable,Int] = Right(42) 

continuación, puede utilizar fold o un mapa a una opción o lo que sea más te gusta hacer con eithers.

Tenga en cuenta que puede definir un único receptor y poder usarlo varias veces (por lo que no es necesario para crear el objeto receptor cada vez que, por ejemplo, analizar un número entero):

scala> val catcher = catching(classOf[NFE]) 
catcher: util.control.Exception.Catch[Nothing] = Catch(java.lang.NumberFormatException) 

scala> catcher.opt("42".toInt) 
res4: Option[Int] = Some(42) 

scala> catcher.opt("fish".toInt) 
res5: Option[Int] = None 

Editar: como Daniel señala en los comentarios, esto todavía crea un Catch[Option] temporal; dadas las firmas de método, no hay una manera fácil de hacer que atrape excepciones y genere opciones sin crear ningún objeto adicional. Esto me recuerda por qué escribo mis propios métodos para hacer exactamente eso:

def optNFE[T](t: => T) = try { Some(t) } catch {case nfe: NFE => None} 
optNFE("fish".toInt) // gives None 
optNFE("42".toInt) // gives Some(42) 
+0

Gracias Rex! Voy a poner esto en buen uso :) – Geo

+0

Esto es realmente útil. Ni idea de que existió. Gracias por el comentario. – overthink

+6

En realidad, 'catching' no devolverá' Catch [NFE] ', sino' Catch [Nothing] '. El parámetro de tipo o 'Catch' indica qué puede devolver en caso de excepción. Por ejemplo, 'withApply' toma una función' Throwable => U', y devuelve un 'Catch [U]'. El método 'opt' primero usará' toOption' para obtener 'Catch [Option [X]]' que devuelve 'None' si se lanza una excepción, y luego pasa' Some (body) 'a ese receptor. –

0

utilizo un patrón más simple cuando sólo hay un inconveniente:

try{ 
     return args.split(" ").exists(line.startsWith _) 
}catch { 
    case _ =>{//generic exception 
     logger.error("Error with line ${line} for ${ex.message}") 
     throw _ 
    }  
} 

definitivamente estoy todavía no es un pro Scala , y creo que podrías encontrar cosas más cortas