指令如何在Spray中工作?

时间:2015-01-05 10:32:49

标签: spray

我想了解Spray中的指令是如何工作的。 As per the documentation

  

指令的一般解剖如下:

name(arguments) { extractions =>
  ... // inner Route
}

我的基本理解是,在下面的代码段中,32作为参数传递给方法test

test {
  32
}

但是,在上面的指令name示例中,它被称为参数传递到内部路由,这是一个匿名函数。

有人可以帮我理解语法和流程,从如何提取参数并传递到内部路径开始?

1 个答案:

答案 0 :(得分:8)

您的语法正确地将32传递给函数test。你缺少的是Directive 接受函数作为参数(记住,我们现在正在进行函数式编程,因此函数是值)。如果你想写这个:

path(IntNumber) {
  userId =>
    complete(s"Hello user $userId")
}

以较少DSL-ey的方式,你可以这样做:

val innerFunction: Int => Route = {userId => complete(s"Hello user $userId")}
(path(IntNumber))(innerFunction)

甚至是这样:

def innerMethod(userId: Int): Route = complete(s"Hello user $userId")
(path(IntNumber))(innerMethod)

实际完成这项工作的机制是......复杂;此方法使Directive可隐式转换为函数:

implicit def pimpApply[L <: HList](directive: Directive[L])(implicit hac: ApplyConverter[L]): hac.In ⇒ Route = f ⇒ directive.happly(hac(f))

这是使用“磁体模式”来选择一个合适的hac,这样如果指令提取参数或者一个值,它就可以在内部路径中使用一个函数(具有适当数量的参数)如果指令不提取参数,则为内部路径(普通路径)。代码看起来比它复杂,因为scala没有直接支持完全依赖类型,所以我们必须通过implicits来模拟它。有关这个必要的可怕代码,请参阅ApplyConverterInstances:/。

当我们在特定指令的happly方法中获得实际路线时,实际提取全部发生。 (如果到处都使用了HList,我们大多可以避免/忽略前面的恐怖事件)。大多数extract-ey指令(例如path)最终会调用hextract

def hextract[L <: HList](f: RequestContext ⇒ L): Directive[L] = new Directive[L] {
  def happly(inner: L ⇒ Route) = ctx ⇒ inner(f(ctx))(ctx)
}

请记住,Route实际上只是RequestContext => Unit,因此当传递Route时会返回RequestContext

  1. 在其上运行f,以提取需要提取的内容(例如网址路径组件)
  2. 上运行inner ; inner是例如ApplyConverter的函数。路径组件到内部路径。
  3. 在上下文中运行内部路径。
  4. (以下是通过评论对话的mod编辑的):

    从根本上说它非常优雅,你可以看到所有的喷码和普通的scala代码(我真的建议你在困惑时阅读源代码)。但是{{1}}的“桥接”部分是复杂的,而且实际上没有办法解决这个问题。它试图用一种并非真正为它们设计的语言来完全依赖类型。

    你必须记住,喷涂路由DSL是DSL;这是几乎任何其他语言中你必须拥有的外部配置文件。我想不出一个单一的Web框架在路由定义方面提供了相同的灵活性,喷涂可以实现完整的编译时类型安全性。所以是的,喷涂的一些东西很复杂 - 但正如引用的那样,容易的东西应该是容易的,而且应该是可能的。所有scala级别的东西都很简单;喷雾是复杂的,但在另一种语言中会更复杂(不可思议)。