【问题标题】:Scala: pattern matching Option with case classes and code blocksScala:带有案例类和代码块的模式匹配选项
【发布时间】:2015-05-13 15:44:07
【问题描述】:

我开始学习伟大的 Scala 语言并且对“深度”模式匹配有疑问

我有一个简单的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")
    }
}

看,我在case 语句中使用requestOrNone.get 来获取动作Request 对象。它类型安全吗,因为case 语句匹配?我觉得有点丑。是否可以从Some“解包”Request 对象,但仍然能够匹配Request 类字段?

如果我想在带有局部变量等的case 内进行复杂计算怎么办...我可以在case 语句之后使用{} 块吗?我使用带有官方 Scala 插件的 IntelliJ Idea,它会突出显示我的括号,建议删除它们。

如果可能的话,将匹配项包含在匹配项中是否是一种好习惯?

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

【问题讨论】:

    标签: scala pattern-matching


    【解决方案1】:

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

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

    模式绑定器 x@p 由模式变量 x 和模式 p 组成。 变量 x 的类型是模式 p 的静态类型 T。这个 模式匹配任何与模式 p 匹配的值 v,前提是 v 的运行时类型也是 T 的一个实例,它绑定了 该值的变量名。

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

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      您不能在模式中使用代码块,只能使用保护 (if ...)。

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

      【讨论】:

      • 你能指出我解释@ 的文档页面吗?我试着用谷歌搜索它
      • 别名是 scala 语法的一部分(内置,不是来自插件):case aliasA @ PatExpr(_, subAlias @ PatExpr(_, _)) => println(s"$aliasA / $subAlias")
      猜你喜欢
      • 1970-01-01
      • 2017-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-25
      • 2014-08-12
      • 2013-09-13
      相关资源
      最近更新 更多