我是Scala的新手,试图理解模式匹配结构的语法,特别是来自Unfiltered(http://unfiltered.databinder.net/Try+Unfiltered.html)中的示例。Scala/Unfiltered中的模式匹配语法
这是一个简单的HTTP服务器,可以回显Hello World!和2份的路径,如果该路径是2份长:
package com.hello
import unfiltered.request.GET
import unfiltered.request.Path
import unfiltered.request.Seg
import unfiltered.response.ResponseString
object HelloWorld {
val sayhello = unfiltered.netty.cycle.Planify {
case GET(Path(Seg(p :: q :: Nil))) => {
ResponseString("Hello World! " + p + " " + q);
}
};
def main(args: Array[String]) {
unfiltered.netty.Http(10000).plan(sayhello).run();
}
}
同样为了参考的路径,波段的源代码,和GET /方法对象:
package unfiltered.request
object Path {
def unapply[T](req: HttpRequest[T]) = Some(req.uri.split('?')(0))
def apply[T](req: HttpRequest[T]) = req.uri.split('?')(0)
}
object Seg {
def unapply(path: String): Option[List[String]] = path.split("/").toList match {
case "" :: rest => Some(rest) // skip a leading slash
case all => Some(all)
}
}
class Method(method: String) {
def unapply[T](req: HttpRequest[T]) =
if (req.method.equalsIgnoreCase(method)) Some(req)
else None
}
object GET extends Method("GET")
我能够打破怎样大部分工作,但此行让我百思不得其解:
case GET(Path(Seg(p :: q :: Nil))) => {
我理解代码的目的,但这样做的不是如何应用。我非常有兴趣了解Scala的各种细节,而不是简单地使用它来实现一个HTTP服务器,所以我一直在深入研究它几个小时。我明白,这事做对了GET
,Path
和Seg
对象提取和unapply
方法,我也知道,当我调试它击中在GET
unapply
Seg
之前Path
和Path
之前。
我不明白下面的事情:
为什么我不能写
GET.unapply(req)
,但我可以写GET(req)
或GET()
,它会匹配任何HTTP GET?为什么编译器知道什么值会传递给每个提取器的
unapply
方法?看起来它会将它们链接在一起,除非其中一个返回None
而不是Some
?它如何绑定变量p和q?它知道它们是字符串,它必须从返回类型
Seg.unapply
推断出来,但我不明白将p分配给列表第一部分的值的机制,以及q列表的第二部分的值。有没有办法改写它,使其更清楚发生了什么?当我第一次看到这个例子时,我被
val sayhello = unfiltered.netty.cycle.Planify {
弄糊涂了,我找到并重写了它,发现它隐式地创建了一个PartialFunction并将它传递给了Planify.apply。