【问题标题】:Generating lazy scala streams by iteration通过迭代生成惰性 Scala 流
【发布时间】:2015-11-27 00:31:21
【问题描述】:

我正在寻找一种方法来生成这种形式的 scala 流(相当于 F# 的序列):

let allRows resultSet : seq<Row> =
  seq {
    while resultSet.next() do
      yield new Row(resultSet)
  }

有没有办法在 scala 中轻松做到这一点?我发现涉及(非尾递归)递归的唯一方法,对于resultSet 中的大量行,这意味着某些堆栈溢出。

谢谢

【问题讨论】:

  • 您确定要使用 Scala Stream 吗?延迟计算后,它将所有结果保存在内存中。听起来 F# 序列更类似于 Scala 迭代器,它一次懒惰地产生一个值,只保留内存中的当前值。
  • 我正在寻找与 F# 序列相同的行为。我的印象是,它们在 Scala 中的等价物大致是 Streams(它们的合同似乎在某种程度上暗示了它们的懒惰性质)。我错了吗?

标签: scala f# functional-programming


【解决方案1】:

你可以这样实现:

 def toStream(rs:ResultSet):Stream[Row] =
   if(!rs.next) Stream.Empty
   else new Row(rs) #:: toStream(rs)

请注意,由于 toStream 是使用 def 定义的(与使用 val 的定义相反),此解决方案不会将整个流保留在内存中,并且流的头部将被垃圾收集。

您可以使用的另一个选项是定义新的迭代器:

def toIterator(rs:ResultSet) = new Iterator[Row] {
  override def hasNext: Boolean = rs.next()
  override def next(): Row = new Row(rs)
}

【讨论】:

  • 你好。如 OP 中所述,我正在寻找尾递归解决方案(如果使用某种递归实现)。如果我没记错的话,您的流解决方案不是尾递归的,并且会炸毁您的堆栈以获得足够大的结果集。
  • 啊,这是一件有趣的事情。我会阅读你给我的链接,今晚我会回复你。
【解决方案2】:

假设你有类似的东西

trait ResultSet {
  def next: Boolean
}

class Row(rs: ResultSet)

你可以将你的函数定义为

def allRows(rs: ResultSet): Stream[Row] =
  Stream.continually(if (rs.next) Some(new Row(rs)) else None)
    .takeWhile(_.isDefined).map(_.get)

【讨论】:

  • 我喜欢这个实现。
猜你喜欢
  • 2012-09-20
  • 1970-01-01
  • 2013-01-02
  • 2016-09-13
  • 2011-01-07
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
相关资源
最近更新 更多