试图理解Scala枚举器/迭代

时间:2016-09-26 11:27:13

标签: scala playframework-2.0

我是Scala和Play!的新手,但是在使用Django和Python以及编程方面拥有合理的构建webapps的经验。

我一直在努力练习提高自己的理解力 - 只需从数据库中提取一些记录并将其作为JSON数组输出。我正在尝试使用Enumarator / Iteratee功能来执行此操作。

我的代码如下:

TestObjectController.scala:

  def index = Action {
    db.withConnection { conn=>
      val stmt = conn.createStatement()
      val result = stmt.executeQuery("select * from datatable")

      logger.debug(result.toString)
      val resultEnum:Enumerator[TestDataObject] = Enumerator.generateM {
        logger.debug("called enumerator")
        result.next() match {
          case true =>
            val obj = TestDataObject(result.getString("name"), result.getString("object_type"),
              result.getString("quantity").toInt, result.getString("cost").toFloat)
            logger.info(obj.toJsonString)
            Future(Some(obj))
          case false =>
            logger.warn("reached end of iteration")
            stmt.close()
            null
        }
      }

      val consume:Iteratee[TestDataObject,Seq[TestDataObject]] = {
        Iteratee.fold[TestDataObject,Seq[TestDataObject]](Seq.empty[TestDataObject]) { (result,chunk) => result :+ chunk }
      }

      val newIteree = Iteratee.flatten(resultEnum(consume))
      val eventuallyResult:Future[Seq[TestDataObject]] = newIteree.run
      eventuallyResult.onSuccess { case x=> println(x)}
      Ok("")

    }
  }

TestDataObject.scala:

package models

case class TestDataObject (name: String, objtype: String, quantity: Int, cost: Float){
  def toJsonString: String = {
    val mapper = new ObjectMapper()
    mapper.registerModule(DefaultScalaModule)
    mapper.writeValueAsString(this)
  }
}

我有两个主要问题:

  • 如何从Enumerator回调中发出输入完成的信号?文档说“这个方法需要一个回调函数e:=> Future [Option [E]],每次应用这个Enumerator的iteratee时都会调用它来准备接受一些输入。”但是我无法通过任何我发现的EOF,因为它是错误的类型。将它包装在未来并没有帮助,但本能地我不确定这是正确的方法。

  • 如何从控制器视图中返回Future的最终结果?我的理解是,我实际上需要暂停主线程等待子线程完成,但我见过的唯一例子,我在未来的类中找到的只是onSuccess回调 - 但我怎么能那么从视图中返回? Iteratee.run是否阻塞,直到所有输入都被消耗?

还有几个子问题,以帮助我理解:

  • 为什么我需要将对象包含在Some()中,当它已经存在于Future中时? Some()究竟代表什么?
  • 当我第一次运行代码时,我从logger.info中获取一条记录,然后报告“到达迭代结束”。在同一会话中的后续运行不会调用任何内容。我虽然关闭了这个陈述,为什么第二次没有结果呢?我期待它无限循环,因为我不知道如何发出正确的循环终止信号。

非常感谢你提出任何答案,我认为我已经掌握了这个问题,但显然还没有!

1 个答案:

答案 0 :(得分:0)

  

如何从Enumerator回调中发出输入完成信号?

您返回Future(None)

  

如何从控制器视图中返回Future的最终结果?

您可以使用Action.asyncdoc):

def index = Action.async {
  db.withConnection { conn=>
    ...
    val eventuallyResult:Future[Seq[TestDataObject]] = newIteree.run
    eventuallyResult map { data =>
      OK(...)
    }
  }
}
  

为什么我的对象已经在未来时需要将我的对象包装在Some()中? Some()究竟代表什么?

Future表示获取下一个元素的(可能是异步的)处理。 Option代表下一个元素的可用性:Some(x)如果另一个元素可用,None如果枚举完成。