14

我在数据库中有一组行,我想提供一个界面来像这样旋转它们:

def findAll: Iterable[MyObject]

我们不需要一次将所有实例都保存在内存中。在 C# 中,您可以使用 yield 轻松创建像这样的生成器,编译器负责将循环通过记录集的代码转换为迭代器(有点反转它)。

我当前的代码如下所示:

def findAll: List[MyObject] = {
  val rs = getRs
  val values = new ListBuffer[MyObject]
  while ( rs.next() ) 
    values += new valueFromResultSet(rs)
  values.toList
}

有没有办法可以将其转换为不将整个集合存储在内存中?也许我可以使用 for 理解?

4

3 回答 3

15

我遇到了同样的问题,基于上面的想法,我通过简单地编写一个适配器类创建了以下解决方案:

class RsIterator(rs: ResultSet) extends Iterator[ResultSet] {
    def hasNext: Boolean = rs.next()
    def next(): ResultSet = rs
}

有了这个,您可以例如对结果集执行映射操作 - 这是我个人的意图:

val x = new RsIterator(resultSet).map(x => {
    (x.getString("column1"), x.getInt("column2"))
})

附加 a.toList以强制评估。如果在使用这些值之前关闭数据库连接,这很有用。否则,您将收到一条错误消息,提示您在连接关闭后无法访问 ResultSet。

于 2013-04-11T13:50:58.597 回答
13

尝试扩展迭代器。我还没有测试过,但是是这样的:

def findAll: Iterator[MyObject] = new Iterator[MyObject] {
  val rs = getRs
  override def hasNext = rs.hasNext
  override def next = new valueFromResultSet(rs.next)
}

这应该在调用时存储 rs,否则只是对 rs 的调用的轻包装。

如果要保存遍历的值,请查看 Stream。

于 2010-01-20T16:32:09.880 回答
6

实现相同目标的更简单(惯用)方法是

Iterator.continually((rs.next(), rs)).takeWhile(_._1).map(r => valueFromResultSet(r._2)).toList

您需要.toList强制评估,否则基础集合将是一个流,并且 ResultSet 可能会在评估发生之前关闭。

于 2014-11-10T07:31:57.580 回答