2012-04-11 9 views
7

Me encuentro repitiendo bloques simples try/catch que deberían, IMO, ser 1-liners.Scala DRYing try/catch

Por ejemplo, supongamos que necesito convertir una fecha de uri string en formato aaaammdd a Joda-Time. Con un try/catch estándar bloquear el método de conversión se ve así:

def ymd2Date(ymd: Option[String]) = ymd match { 
    case Some(date) => 
    try { Right(ymdFormat.parseDateTime(date)) } 
    catch { case e => 
     log.info(e.getMessage) 
     Left(None) 
    } 
    case None => 
    Left(None) // no uri date param 
} 
val ymdFormat = DateTimeFormat.forPattern("yyyyMMdd") 

funciona bastante bien, la intención es clara, pero cuando lo haga este tipo de try/catch registro para todos eventos sin gravedad, entonces yo busca una forma de SECARLO. La búsqueda me llevó a este SO post en scala.util.control.Exception. Útil, pero aún es un poco difícil asimilarlo/hacerlo funcionar de la manera que me gustaría. En lenguaje simple solo quiero decir, "atrapar algo de acción obtener resultado log-error-type".

lo tanto, me han pirateado esto en base a la parte de control.Exception Me interesa (o entender para ser útil):

class Catcher[T](f: => T) { 
    type Logger = (=> Any) => Unit 

    def either[T](logger: => Logger) = { 
    try { Right(f) } 
    catch { case e => 
     logger(e.getMessage) 
     Left(None) 
    } 
    } 
} 
def catching[T](f: => T) = new Catcher(f) 

y luego usar en lugar del try/catch de este modo:

catching(ymdFormat.parseDateTime(date)) either log.info 

puede añadir en opción, un prefijo msg, etc., pero ... probablemente sería mejor encontrar una manera de conseguir control.Exception funcione como el de arriba, mientras que el equipo va a typesafe producir mundos de código mejor de lo que alguna vez imaginaría escribir.

¿Alguien sabe cómo crear este tipo de sintaxis usando control. ¿Existe una excepción en la que se puede pasar un nombre de función de registrador para usar en el bloque catch?

Sería muy bueno si había una "casos de uso" para control.Exception, pero tengo la sensación de esta utilidad es para más desarrolladores avanzados Scala

+3

¿Por qué usas 'Oither'? Si todo lo que va a poner en 'Left' es 'None', entonces parece que podría usar 'Option [T]'. – huynhjl

+0

buen punto, quería doblar el resultado y cualquiera de los dos parecía un ajuste natural ... – virtualeyes

+0

, es decir, actualmente no hay opción de plegado, o al menos no está incorporado en el idioma – virtualeyes

Respuesta

7

Esto debería hacer lo que quiera:

import scala.util.control.Exception 
def log(logger: => Logger)(e: Throwable) = { 
    logger(e.getMessage) 
    None 
} 
Exception.allCatch withApply log(logger) apply Some(ymdFormat.parseDateTime(date)) 

Pero este tipo de cosas es mejor manejado por Scalaz Validation, en mi opinión.

+0

a la derecha, todavía tengo que aventurarme por la fila de Scalaz, solo para mojarme los pies en la propia Scala. La validación en su forma más básica se parece a Either, pero luego la curva aumenta rápidamente. Está en la lista de tareas pendientes ... – virtualeyes

+0

es genial, por cierto, parece que puedo eliminar mi hack y adoptar un enfoque que alguien que no sea yo entenderá ;-) – virtualeyes

+2

@virtualeyes - Por lo que vale, tu "truco" es mucho más claro para mí que el enfoque de Daniel (sería aún más claro si no lo llamaras "captura" sino más bien "tryOrLog" o algo que no sugiera que el primer argumento sea atrapado). –

3

Un ejemplo rápido:

import scala.util.control.Exception._ 

def throwingStuff { 
    throw new Exception("Hello World!") 
} 

catching(classOf[Exception]).withApply{err => println(err.toString); None}.apply(Some(throwingStuff)) 

Puede use withApply para anular la lógica de la aplicación de la clase Catch para hacer algo como escribir en un registro.

+0

El tipo de devolución no es del todo trabaja con esto 'withApply' convierte el' Throwable' en un valor de retorno, por lo que nunca obtendrás 'Left', y' Right' será 'Any' o' AnyRef'. –

+0

¡Sí, realizado y editado justo antes de tu comentario! Sin embargo, usar 'Some' es una buena idea. – Submonoid

+0

Necesito preservar el tipo. Si voy a la Opción [T], ¿el tipo será preservado/accesible? – virtualeyes