ActionBuilder接受IO [Result]而不是Future [Result]

时间:2015-01-27 14:04:33

标签: scala scalaz playframework-2.3

我写了一个小例子,在play框架中使用scalaz的IO monad。以下示例按预期工作:

object IOAction {
  def apply(action:IO[Result]):Result = action.unsafePerformIO
}

class ExampleController extends Controller {
  val now:IO[DateTime] = IO { DateTime.now }

  def index = Action { request => 
    IOAction { 
      now.map { dateTime => Ok(views.html.index(dateTime)) }
    }
  }
}

但是,我想知道使用PlayBuilder是否会导致一个稍微冗长的API。理想情况下,我想写:

class ExampleController extends Controller {
  val now:IO[DateTime] = IO { DateTime.now }

  def index = IOAction { request => 
    now.map { dateTime => Ok(views.html.index(dateTime)) }
  }
}

我卡住了,因为invokeBlock函数似乎已修复为Future[Result]类型。

def invokeBlock[A](request: R[A], block: P[A] => Future[Result]): Future[Result]

有没有人知道IOAction行为与Action相同的解决方法(即可选的请求参数和正文解析器)?

1 个答案:

答案 0 :(得分:2)

如果您重新定义IOAction,那么后一个示例是否有效:

object IOAction {
  def apply(io: Request[AnyContent] => IO[Result]): Action[AnyContent] =
    Action { (request: Request[AnyContent]) => io(request).unsafePerformIO }
}

Controller对象中你可以做

def foo(): Handler = IOAction { request =>
  Ok("foo").point[IO]
}

即。 Future是异步(IO)计算,其中IO是同步的。从IOFuture的转换很容易。


IOActionBuilder的组合并不适合锻炼。 ActionBuilder并未考虑IO。它有

final def apply(block: ⇒ Result): Action[AnyContent]
final def apply(block: (R[AnyContent]) ⇒ Result): Action[AnyContent]
final def async(block: ⇒ Future[Result]): Action[AnyContent]
final def async(block: R[AnyContent]) ⇒ Future[Result]): Action[AnyContent]

你可以制作一个延伸ActionBuilder[R]的特征并提供,比如说:

final def io(block: => Result): Action[AnyContent]
final def io(block R[AnyContent] => Result): Action[AnyContent]

然后你可以定义:

object IOAction extends IOActionBuilder[Request] { /* ... */ }

并将其用作:

 def foo = IOAction.io { request => 
   Ok("foo").point[IO]
 }

这与我们首先定义的几乎完全相同,但不是那么直接。


ActionComposition.scala感兴趣的是 撰写动作,不提供基本动作