2

考虑以下使用循环在 Scala 中清空队列的草图:

var queue = immutable.Queue[T]( /* .. some content ..*/ )
while( !queue.isEmpty ) {
   val (record, tempQueue) = queue.dequeue
   queue = tempQueue
   doSomethingWith(record)
}

有什么技巧可以避免临时变量tempQueue并让 Scala 将返回的 Queue 值直接分配给循环变量queue?必须引入额外的符号很烦人,而且可能会有一些多余的复制(尽管这可能会被优化掉,不确定)。

编辑 1:当然,正如 Ionut G. Stan 指出的那样,我可以跳过模式匹配并自己拆开返回的对,如下所示:

while( !queue.isEmpty ) {
   val pair = queue.dequeue
   queue = pair._2
   doSomethingWith(pair._1)
}

所以我应该把这个问题细化如下:有没有办法使用模式匹配的语法糖来更优雅地做到这一点?我希望有这样的东西,不幸的是它没有编译:

var queue = immutable.Queue[T]( /* .. some content ..*/ )
var record : A = _
while( !queue.isEmpty ) {
   (record, queue) = queue.dequeue
   doSomethingWith(record)
}
4

7 回答 7

3

如果您坚持保持该结构(while循环等),我看不出如何使其更短,除非:

var queue = immutable.Queue[T]( /* some content */ )
while( !queue.isEmpty ) queue.dequeue match {
  case (record, tempQueue) =>
    queue = queue.dequeue
    doSomethingWith(record)
}

但是,由于您使用的是不可变队列,因此最简单的等效代码可能是:

for(record <- queue) {
  doSomethingWith(record)
}

另请参阅此相关问题,该问题确认无法分配给预先存在var的模式匹配表示法。

Scala 语言规范第4.1 节也很清楚:模式匹配样式的赋值扩展为val定义,即它们将绑定一个新的标识符。

于 2011-12-20T14:29:15.410 回答
2

您正在使用带有不可变的 while 循环Queue。为什么不使用更实用的方法(因为无论如何你都有一个不可变Queue的)?

您可以定义要在其中的每个项目上运行的函数Queue,然后使用集合操作(​​映射等,具体取决于您想要的返回)来应用它。

例如

  import scala.collection.immutable._

  val q = Queue[(Int,Int)]((1,2),(3,4),(5,6))

  def doSomethingWith(a:(Int,Int)) = {
    a swap
  }

  //returns a new Queue with each tuple's elements swapped
  q map doSomethingWith

  //returns unit (so only useful if doSomethingWith has a side effect)
  q foreach doSomethingWith   
于 2011-12-20T14:45:10.187 回答
2

对于不可变的数据结构,递归是 FP 做事的方式。

def foo[T](queue: immutable.Queue[T]) {
  if (!queue.isEmpty) {
    val (record, remaining) = queue.dequeue
    doSomethingWith(record)
    foo(remaining)
  }
}

foo(queue)queue foreach doSomethingWith与Brian Smith 建议的基本相同。

于 2011-12-20T16:12:47.563 回答
1

您可以使用_最多可用的前缀成员Tuple22

scala> val a = (1,2)
a: (Int, Int) = (1,2)

scala> a._1
res0: Int = 1

scala> a._2
res1: Int = 2
于 2011-12-20T13:54:12.503 回答
0

根据条件,您可以先过滤列表,或者使用 takeWhile 然后映射结果集。就像是

(queue takeWhile condition) foreach operation

或者

(queue withFilter condition) foreach operation

这仅在条件是单个元素的函数时才有效。您还可以通过折叠来累积您想要的部分(可能看起来像:)

(Nil /: queue)(<add element to accumulator if needed>) foreach operation
于 2011-12-20T19:56:21.827 回答
0

这是模式匹配,但它仍然引入了临时变量。

while( !queue.isEmpty ) {
  queue = queue.dequeue match {
    case (t: T, q: immutable.Queue[T]) =>      
      doSomethingWith(t)
      q
  }
}
于 2011-12-20T14:44:32.867 回答
0

这是一个小技巧:

queue forall doSomethingWith

假设doSomethingWith是类型T => Boolean

于 2011-12-20T16:06:26.243 回答