Scala:模式匹配选项与案例 类 和代码块

Scala: pattern matching Option with case classes and code blocks

我开始学习很棒的 Scala 语言,我有一个关于 "deep" 模式匹配的问题

我有一个简单的 Request class:

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")
    }
}

看,我在 case 语句中使用 requestOrNone.get 来获取操作 Request 对象。它是类型安全的,因为 case 语句匹配吗?我觉得有点丑。这是从 Some "unwrap" Request 对象但仍然能够匹配 Request class 字段的方法吗?

如果我想在 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)
      }
  }
}

您可以如下重写模式(使用别名)。

case Some(req @ Request(_, _, _)) => new Response(405, "Method Not Allowed", req)

模式中不能使用代码块,只能使用守卫(if ...)。

有像rich pattern matching这样的模式匹配编译器插件。

对于问题的第一部分,您可以将匹配的值命名为 @ :

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 Specifications8.1.3:模式绑定器):

A pattern binder x@p consists of a pattern variable x and a pattern p. The type of the variable x is the static type T of the pattern p. This pattern matches any value v matched by the pattern p, provided the run-time type of v is also an instance of T , and it binds the variable name to that value.

但是,在您的示例中,您 不需要 :因为您没有匹配 Request 的任何内容,而只是它的存在,您可以这样做:

case Some(req) => new Response(405, "Method Not Allowed", req)

对于第二部分,您可以嵌套 matches。 Intellij 建议删除大括号的原因是它们是不必要的:关键字 case 足以知道前面的 case 已经完成。

至于这是否是一个好的做法,这显然取决于具体情况,但我可能会尝试将代码重构为更小的块。