2011-10-08 11 views
22

Actualmente estoy dando mis primeros pasos en Scala, así que estoy buscando las mejores prácticas para abordar los problemas comunes. A continuación está el código que no funciona pero describe lo que quiero hacer. ¿Podría recomendar el mejor enfoque para este problema?Scala string pattern matching best practice

def resolveDriver(url: String) = { 
    url match { 
     case url.startsWith("jdbc:mysql:") => "com.mysql.jdbc.Driver" 
     case url.startsWith("jdbc:postgresql:") => "org.postgresql.Driver" 
     case url.startsWith("jdbc:h2:") => "org.h2.Driver" 
     case url.startsWith("jdbc:hsqldb:") => "org.hsqldb.jdbcDriver" 
     case _ => throw new IllegalArgumentException 
    } 
    } 
+2

Véase también [esta cuestión] (http://stackoverflow.com/q/7586605/53013) otra manera de resolver este problema, si la parte coincidente pasa a ser todo el protocolo. –

Respuesta

39

En términos de sintaxis, puede modificar sólo un poco que las declaraciones de caso:

case url if url.startsWith("jdbc:mysql:") => "com.mysql.jdbc.Driver" 

Esto simplemente enlaza el valor url a la expresión del modelo (que es también url) y añade un guardia expresión con una prueba. Eso debería hacer que el código se compile.

para que sea un poco más Scala similar, puede devolver una opción [String] (He quitado una cláusula de pareja ya que es sólo para la ilustración):

def resolveDriver(url: String) = url match { 
    case u if u.startsWith("jdbc:mysql:") => Some("com.mysql.jdbc.Driver") 
    case u if u.startsWith("jdbc:postgresql:") => Some("org.postgresql.Driver") 
    case _ => None 
} 

Eso es menos que desea administrar excepciones

+0

¡Gracias! ¡Eso es exactamente lo que estaba buscando! Me alegro de haber preguntado porque yo ya me estaba preparando para crear una clase de casos para eso, que olía a complicación. También le agradezco por corregirme en el lanzamiento de Exception. –

10

Aquí hay una manera alternativa. Almacene todas las asignaciones en un mapa y luego use el método collectFirst para encontrar la coincidencia. Tipo de firma del collectFirst es:

def TraversableOnce[A].collectFirst[B](pf: PartialFunction[A, B]): Option[B] 

Uso:

scala> val urlMappings = Map("jdbc:mysql:" -> "com.mysql.jdbc.Driver", "jdbc:postgresql:" -> "org.postgresql.Driver") 
urlMappings: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(jdbc:mysql: -> com.mysql.jdbc.Drive 
r, jdbc:postgresql: -> org.postgresql.Driver) 

scala> val url = "jdbc:mysql:somestuff" 
url: java.lang.String = jdbc:mysql:somestuff 

scala> urlMappings collectFirst { case(k, v) if url startsWith k => v } 
res1: Option[java.lang.String] = Some(com.mysql.jdbc.Driver) 
+0

Gracias, pero no es lo que propone una abstracción sobre 'match'? –

+0

@mojojojo: No del todo. El conjunto de expresiones 'case' que sigue a 'match' constituye una' PartialFunction'. 'collectFirst' es un método que acepta una' PartialFunction', recorre la colección y devuelve la primera coincidencia encontrada como envuelta en 'Some'. (devuelve 'Ninguno' si no se encontró ninguna coincidencia). – missingfaktor

+0

@mojojojo: Ver la fuente: http://goo.gl/Q4UNz – missingfaktor