Scala:将结果集转换为不同类型的多重映射

发布于 2024-10-30 19:07:47 字数 1554 浏览 3 评论 0原文

我将在 Scala 中创建 JDBC ResultSet 的包装器。
这个包装器旨在成为一个函数 ResultSet =>特定类型
问题是我找不到制作多重地图的通用解决方案。

这是我获取集合的方式:

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

问题是我不能在 Place for V 处使用 V 因为那时还没有声明。
我觉得抽象类型是一个很好的解决方案,但不知道如何正确对待它们。

这样的收藏创作正确的方式是什么?

我也不确定是否可以覆盖已在类层次结构中更高层定义的抽象类型。

I am going to create wrapper over JDBC ResultSet in Scala.
This wrapper is intended to be a function ResultSet => ParticularType.
The problem is I can't find a common solution for making MultiMaps.

Here is the way I am fetching collections:

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 
}

Next goes maps creation. It is an implementation of collection creation and it is not abstract due to map non-abstractness (it is always backended with HashMap in my implementation).
In my opinion, it should look like this:

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
}

If it works, I would write ListMultiMap creation this way:

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

The problem is I can't use V at Place for V because it is not declared then.
I feel like abstract types is the good solution but don't know how to treat them right.

What is the correct way of such a collections creation?

I am also not sure if it is possible to override abstract types that were already defined higher in the class hierarchy.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风透绣罗衣 2024-11-06 19:07:47

在您的定义中,MapCreator 实际上将 IVV 限制为相同类型。根据约定,Map[K,V] 中返回的 V 必须与 valueCreator 返回的类型相同。例如,如果我打电话:

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

我希望得到一个 Map[String,String]。如果扩展MapCreator,则无法更改该关系。如果您想要一个 Map[String,List[String]] 您需要提供一个 (ResultSet) => 类型的 valueCreator列表[字符串]

考虑到这一点,您可以像这样更改定义和实现:

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) 中,如果结果集为空怎么办?

In your definition, MapCreator is really constraining IV and V to be the same type. By contract the V returned in Map[K,V] has to be the same type as the type returned by valueCreator. For instance, if I called:

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

I would expect to get a Map[String,String]. You cannot change that relation if you extend MapCreator. If you want a Map[String,List[String]] you need to supply a valueCreator of type (ResultSet) => List[String].

With that in mind you can change the definition and implementation like this:

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

I feel that because CollectionCreator uses a type parameter, that it will be cumbersome to use abstract types. Overall, there seems to be much boiler plate. I would leverage more of the scala libraries:

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

Also in your do { append(rs) } while (rs.next) what if the result set is empty?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文