Соответствие строковому образцу наилучшей практике - PullRequest
26 голосов
/ 08 октября 2011

Ниже приведен код, который не работает, но он описывает, что я хочу сделать.

Не могли бы вы порекомендовать лучший подход к этой проблеме?

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

Ответы [ 3 ]

42 голосов
/ 08 октября 2011

С точки зрения синтаксиса, вы можете изменить лишь крошечный оператор выражения:

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

Это просто связывает значение url с выражением шаблона (которое также url) и добавляетОхранное выражение с тестом.Это должно привести к компиляции кода.

Чтобы сделать его немного более похожим на scala, вы можете вернуть Option [String] (я удалил предложение пары, так как оно только для иллюстрации):

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
}

Это если вы не хотите управлять исключениями.

10 голосов
/ 08 октября 2011

Вот альтернативный способ.Сохраните все сопоставления на карте, а затем используйте метод collectFirst, чтобы найти совпадение.Тип подписи collectFirst:

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

Использование:

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)
3 голосов
/ 06 апреля 2019

Начиная с Scala 2.13, можно сопоставить шаблон с String с , не применяя интерполятор строк :

val s"jdbc:$dialect:$rest" = "jdbc:mysql:whatever"
// dialect: String = "mysql"
// rest: String = "whatever"

Тогда в нашем случае это просто вопрос сопоставления извлеченного значения (диалект sql) соответствующему драйверу, используя Map:

val drivers = Map(
  "postgresql" -> "org.postgresql.Driver",
  "mysql"      -> "com.mysql.jdbc.Driver",
  "h2"         -> "org.h2.Driver"
)
val driver = drivers(dialect)
// driver: String = "com.mysql.jdbc.Driver"

Если вы ожидаете искаженные данные, вы также можете использовать оператор сопоставления:

"jdbc:postgresql:something" match {
  case s"jdbc:$dialect:$rest" => Some(dialect)
  case _                      => None
}
// Option[String] = Some("postgresql")
...