2011-10-08 13 views
22

Attualmente sto facendo i miei primi passi in Scala, quindi sto cercando le migliori pratiche per affrontare i problemi comuni. Di seguito è riportato il codice che non funziona ma descrive ciò che voglio fare. Potresti raccomandare il miglior approccio a questo problema?Esempio di corrispondenza delle stringhe di Scala 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

Vedi anche [questa domanda] (http://stackoverflow.com/q/7586605/53013) per un altro modo per risolvere questo problema, se la parte corrispondente sembra essere l'intero protocollo. –

risposta

39

In termini di sintassi, è possibile modificare caso solo un po 'si dichiarazioni:

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

Questo si lega semplicemente il valore url all'espressione modello (che è anche url) e aggiunge una guardia espressione con un test. Questo dovrebbe far compilare il codice.

Per rendere un po 'più scala-like, è possibile restituire un'Opzione [String] (ho tolto una clausola paio dal momento che è solo per l'illustrazione):

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 
} 

Che è a meno che non si desidera gestire eccezioni.

+0

Grazie! Questo è esattamente quello che stavo cercando! Sono contento di aver fatto la domanda "perché mi stavo già preparando a creare una classe di casi per questo, che puzzava come una complicazione. Inoltre ti ringrazio per avermi corretto nel lancio delle eccezioni. –

10

Ecco un modo alternativo. Memorizzare tutte le mappature in una mappa e quindi utilizzare il metodo collectFirst per trovare la corrispondenza. Tipo firma del collectFirst è:

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

Usage:

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

Grazie ma non è quello che proponi un'astrazione su 'match'? –

+0

@mojojojo: Non proprio. L'insieme di espressioni 'case' che segue' match' costituisce una 'PartialFunction'. 'collectFirst' è un metodo che accetta un' PartialFunction', loop sulla collezione e restituisce la prima corrispondenza trovata come racchiusa in 'Some'. (restituisce 'None' se non viene trovata alcuna corrispondenza.) – missingfaktor

+0

@mojojojo: vedere la fonte: http://goo.gl/Q4UNz – missingfaktor