使用Scala Futures时解决递归问题

时间:2015-09-14 13:36:35

标签: scala recursion async-await future scala.js

在我的工作代码中涉及递归。我试图避免这种情况,因为如果谓词不成立,递归可能会太深。

case class Chan[T]() {
  private var promise: Promise[T] = Promise[T]()

  /** Binds a handler with the "write" in casu update() */
  def this(handler: (T => Unit) => Unit) {
    this
    handler(update)
  }

  def filter(p: (T) => Boolean): Future[T] = {
     apply().flatMap(value => if (p(value)) Future(value) else filter(p))
  }

  def apply(): Future[T] = {
    promise = Promise[T]()
    promise.future
  }

  def update(t: T): Unit = {
    if (!promise.isCompleted) promise.success(t)    
  }
}

问题在于filter方法。当不满足谓词时,将再次调用filter,寻找符合参数的事件。由此堆栈将被填充,前面是StackOverflow: - )。

如何在循环或尾递归调用中重构代码,避免过多的堆栈使用?

1 个答案:

答案 0 :(得分:1)

所以这里是上面提到的解决方案。 我希望这符合你的目的:

case class Chan[T]() {

  private var pendingFilters: List[(T => Boolean, Promise[T])] = List.empty

  /** Binds a handler with the "write" in casu update() */
  def this(handler: (T => Unit) => Unit) {
    this
    handler(update)
  }

  def filter(p: (T) => Boolean): Future[T] = {
    val promise = Promise[T]()
    // add both the predicate and the promise to your pending filters
    synchronized(pendingFilters = p -> promise :: pendingFilters)
    promise.future
  }

  def update(t: T): Unit = {
    synchronized {
      // partition your pending filters into completed and uncompleted ones
      val (completed, pending) = pendingFilters.partition(_._1(t))
      pendingFilters = pending
      completed
    }.foreach{ case (_, promise) =>
      // and finally complete the promises
      promise.trySuccess(t)
    }
  }
}