Scala: ResultSet перевод в различные виды мультикарт - PullRequest
2 голосов
/ 08 апреля 2011

Я собираюсь создать упаковщик поверх JDBC ResultSet в Scala.
Эта обертка предназначена для использования в качестве функции ResultSet => ParticularType.
Проблема в том, что я не могу найти общее решение для создания MultiMaps.

Вот как я собираю коллекции:

abstract class CollectionCreator[C] extends (ResultSet => C) {  
  def apply(rs: ResultSet): C = {  
    do { append(rs) } while (rs.next)  
    returnCollection()  
  }  
  def append(rs: ResultSet)  
  def returnCollection(): C 
}

Далее идет создание карт. Это реализация создания коллекции, и она не является абстрактной из-за неабстрактности карты (в моей реализации она всегда сопровождается HashMap).
На мой взгляд, это должно выглядеть так:

class MapCreator[K,IV](keyCreator: ResultSet => K, valueCreator: ResultSet => IV)
  extends CollectionCreator[Map[K, Place for V]] {

  type V = IV
  val intermediateMap = new HashMap[K, V]

  override def append(rs: ResultSet) {
    appendToMap(keyCreator(rs), valueCreator(rs))
  }

  def appendToMap(key: K, value: IV) {
    intermediateMap(key) = value
  }

  override def returnCollection(): Map[K,V] = intermediateMap.toMap
}

Если это сработает, я напишу создание ListMultiMap следующим образом:

class ListMultiMapCreator[K,IV](keyCreator: ResultSet => K, valueCreator: ResultSet => IV)
  extends MapCreator[K, Place for V](keyCreator, valueCreator) {

  override type V = List[IV]

  override def appendToMap(key: K, value: IV) {
    intermediateMap(key) = intermediateMap.get(key) match {
      case Some(values) => values.::(value)
      case None         => List(value)
    }
  }
}

Проблема в том, что я не могу использовать V в Place for V, потому что тогда он не объявлен.
Мне кажется, что абстрактные типы - это хорошее решение, но я не знаю, как с ними правильно обращаться.

Как правильно создавать такие коллекции?

Я также не уверен, возможно ли переопределить абстрактные типы, которые уже были определены выше в иерархии классов.

1 Ответ

2 голосов
/ 08 апреля 2011

В вашем определении MapCreator действительно ограничивает IV и V одним и тем же типом.По контракту V, возвращаемое в Map[K,V], должно быть того же типа, что и тип, возвращаемый valueCreator.Например, если бы я позвонил:

MapCreator((rs:ResultSet) => rs.getString("KEY"),
    (rs:ResultSet) => rs.getString("VALUE"))(resultSet)

, я бы ожидал получить Map[String,String].Вы не можете изменить это отношение, если продлите MapCreator.Если вы хотите Map[String,List[String]], вам нужно предоставить valueCreator типа (ResultSet) => List[String].

Имея это в виду, вы можете изменить определение и реализацию следующим образом:

class MapCreator[K,IV](keyCreator: ResultSet => K, 
    valueCreator: ResultSet => IV) extends CollectionCreator[Map[K, IV]] { 
  val intermediateMap = new HashMap[K, IV]
  def append(rs: ResultSet) { appendToMap(keyCreator(rs), valueCreator(rs)) }
  def appendToMap(key: K, value: IV) { intermediateMap(key) = value }
  def returnCollection(): Map[K, IV] = intermediateMap.toMap
}

class ListMultiMapCreator[K,IV](keyCreator: ResultSet => K, 
    elemCreator: ResultSet => IV) extends 
  MapCreator[K, List[IV]](keyCreator, 
      (rs:ResultSet) => List(elemCreator(rs))) {
  override def appendToMap(key: K, value: List[IV]) {
    intermediateMap(key) = intermediateMap.get(key) match {
      case Some(values) => values.:::(value)
      case None         => value
    }
  }
}

Я чувствую, что, поскольку CollectionCreator использует параметр типа, использование абстрактных типов будет затруднительным,В целом, кажется, что есть много котельной плиты.Я бы использовал больше библиотек scala:

def mapCreate[K, IV](rs: ResultSet, 
    keyCreator: ResultSet => K, 
    valueCreator: ResultSet => IV) = {
  Iterator.continually(rs).takeWhile(_.next).map{rs => 
    keyCreator(rs) -> valueCreator(rs)}.toMap
}

def listMultiMapCreate[K, IV](rs: ResultSet, 
    keyCreator: ResultSet => K, 
    valueCreator: ResultSet => IV) = {
  Iterator.continually(rs).takeWhile(_.next).map{rs => 
    keyCreator(rs) -> valueCreator(rs)}.toList.groupBy(_._1)
}

Также в вашем do { append(rs) } while (rs.next), что если набор результатов будет пустым?

...