Listbuffer 行为不直观...如何解决?

Listbuffer behaviour unintuitive... how to solve?

我有一个 ListBuffer[MyClass] 并将其用作队列。

现在考虑以下代码:

private def buildChunks(): Unit =
{
    for(a <- 0 until buildQueue.size)
    {
      val chunk: Chunk = buildQueue(a)
      chunk.init()
    //  buildQueue -= chunk
    //  buildQueue.remove(a)
    }
}

我的理解问题归结为这两行:

buildQueue -= chunk
buildQueue.remove(a)

如果使用它们都会产生 ArrayOutOfBoundsException当然是互斥的没有同时使用它们!)

正如我所说(顾名思义)ListBuffer 用作队列,因此如果处理了一个项目,我想将其从列表中删除。

我不明白为什么这些行会抛出 ArrayOutOfBoundsException

那我应该如何删除项目?

如果你能让我理解这一点,我很乐意使用更漂亮的方法,例如:

val chunk: Chunk = buildQueue.remove(a)

但这当然行不通

你的问题是你在迭代它的值时改变了一个可变集合。

for(a <- 0 until buildQueue.size) 中,buildQueue.size 的值被评估一次,因为 0 until buildQueue.size 创建了一个不可变的 Seq[Int].

现在,如果您的列表缓冲区最初的大小为 5,然后您删除了一个元素,它将以 4 的大小结束。但是,您的循环将迭代直到索引 4,它不再出现在列表缓冲区。

解决此问题的一种方法是使用递归函数:

private def buildChunks(): Unit = {
  @tailrec
  def buildHead(): Unit = {
    buildQueue.headOption match {
      case None ⇒
        () // end of recursion
      case Some(chunk) ⇒
        chunk.init()
        buildQueue -= chunk
        buildHead()
    }
  }

  buildHead()
}

更新:

正如 Teolha 所指出的,您也可以这样做:

private def buildChunks(): Unit = {
   buildQueue.foreach(_.init())
   buildQueue.clear()
}

这更短而且可能更有效。

但是,它不会在 buildChunks() 执行时同时构建 chunks 附加到队列,实际上可能会删除foreach 启动后添加的任何块。