抱歉标题含糊……不知道如何描述这一点。
一段时间以来,我已经在 Scala 中看到/使用了某种代码结构,但我不知道它是如何工作的。它看起来像这样(来自喷雾路由的示例):
path( "foo" / Segment / Segment ) { (a,b) => { // <-- What's this style with a,b?
...
}}
在此示例中,路径中的分段分别绑定(bind)到关联 block 内的 a 和 b。我知道如何使用这种模式,但它是如何工作的?为什么它没有将某些东西绑定(bind)到“foo”?
我对喷雾如何在这里达到我的目的不太感兴趣,但是这是 Scala 的什么工具,我将如何编写自己的工具?
最佳答案
此代码来自扩展 Directives
的类.所以Directives
的所有方法在范围内。
路径匹配器
没有方法/
在 String
, 所以 an implicit conversion用于转换String
至PathMatcher0
( PathMatcher[HNil]
) 与 method /
.
方法/
需要 PathMatcher
并返回 PathMatcher
.
Segment
是 PathMatcher1[String]
(PathMatcher[String :: HNil]
)。
方法/
的 PathMatcher[HNil]
与 PathMatcher[String :: HNil]
参数返回 PathMatcher[String :: HNil]
.
方法/
的 PathMatcher[String :: HNil]
与 PathMatcher[String :: HNil]
参数返回 PathMatcher[String :: String :: HNil]
.这是来自 shapeless
的黑魔法.查看异构列表 concatenation ;值得一读。
指示
所以你调用method path
与 PathMatcher[String :: String :: HNil]
作为参数。它返回一个 Directive[String :: String :: HNil]
.
然后你调用方法 apply
在 Directive
与 Function2[?, ?, ?]
( (a, b) => ..
) 作为参数。每个 Directive[A :: B :: C ...]
都有一个适当的隐式转换(参见黑魔法)。使用方法 apply((a: A, b: B, c: C ...) => Route)
创建一个对象.
解析PathMatcher
包含路径解析规则。它以 HList
的形式返回结果.
"foo"匹配器 matches一个字符串并忽略它(返回 HNil
)。A / B
matcher 结合了 2 个匹配器( A
和 B
),由“/”字符串分隔。它连接 A
的结果和 B
使用 HList
级联。Segment
匹配器 matches路径段并将其作为 String :: HNil
返回.
所以"foo" / Segment / Segment
匹配 3 个段的路径,忽略第一个段并将剩余段返回为 String :: String :: HNil
.
然后黑魔法允许你使用Function2[String, String, Route]
( (String, String) => Route
) 处理 String :: String :: HNil
.如果没有这样的魔法,你将不得不使用这样的方法:{case a :: b :: HNil => ...}
.
黑魔法
正如@AlexIv 所说:
存在隐式转换 pimpApply
对于每个 Directive[A :: B :: C ...]
使用方法 apply((a: A, b: B, c: C ...) => Route)
创建一个对象.
它接受 ApplyConverter
含蓄地。成员(member) In
的 ApplyConverter
表示一个合适的函数(A, B, C ...) => Route
对于每个 Directive[A :: B :: C ...]
.
如果没有宏或样板代码,就无法创建此类隐式值。所以 sbt-boilerplate
用于 ApplyConverter
一代。见 ApplyConverterInstances.scala
.
关于Scala 参数模式(喷雾路由示例),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18395023/