我开始学习伟大的Scala语言ang有关于“深度”模式匹配的问题
我有一个简单的Request
类:
case class Request(method: String, path: String, version: String) {}
一个函数,它尝试匹配request
实例并构建相应的响应:
def guessResponse(requestOrNone: Option[Request]): Response = {
requestOrNone match {
case Some(Request("GET", path, _)) => Response.streamFromPath(path)
case Some(Request(_, _, _)) => new Response(405, "Method Not Allowed", requestOrNone.get)
case None => new Response(400, "Bad Request")
}
}
请参阅我在requestOrNone.get
语句中使用case
来获取操作Request
对象。是否类型安全,因为case
语句匹配?我发现它有点难看。它是一种从Request
“展开”Some
对象的方式,但仍然可以匹配Request
类字段吗?
如果我想在case
内部使用局部变量等进行复杂计算,该怎么办...我可以在{}
语句之后使用case
块吗?我使用IntelliJ Idea与官方Scala插件,它突出显示我的括号,建议删除它们。
如果可以的话,将比赛括起来是不错的做法?
... match {
case Some(Request("GET", path, _)) => {
var stream = this.getStream(path)
stream match {
case Some(InputStream) => Response.stream(stream.get)
case None => new Response(404, "Not Found)
}
}
}
答案 0 :(得分:2)
对于问题的第一部分,您可以使用@
为与之匹配的值命名:
scala> case class A(i: Int)
defined class A
scala> Option(A(1)) match {
| case None => A(0)
| case Some(a @ A(_)) => a
| }
res0: A = A(1)
来自Scala Specifications( 8.1.3:模式文件夹):
图案装订器x @ p由图案变量x和图案p组成。 变量x的类型是模式p的静态类型T.这个 模式匹配模式p匹配的任何值v,条件是 运行时类型v也是T的一个实例,它绑定了 变量名到该值。
但是,在您的示例中,您不需要 :因为您不能与Request
的任何内容进行匹配,而只是匹配它的存在,您可以这样做:
case Some(req) => new Response(405, "Method Not Allowed", req)
对于第二部分,您可以嵌套match
es。 Intellij建议删除大括号的原因是它们是不必要的:关键字case
足以知道之前的case
已完成。
至于它是否是一个好的做法,显然取决于具体情况,但我可能会尝试将代码重构为更小的块。
答案 1 :(得分:0)
您可以按以下方式重写模式(使用别名)。
case Some(req @ Request(_, _, _)) => new Response(405, "Method Not Allowed", req)
您不能在模式中使用代码块,只能使用保护(if ...
)。
有模式匹配编译器插件,如rich pattern matching。