scala的案例保护声明中的变量范围

Deb*_*ski 8 scope scala case pattern-matching partialfunction

对于电梯开发,我有时需要使用match- case如下所示的语句.(为了便于理解,重写为普通scala.)给他们一个注意事项:这些实际上是不同的部分函数,​​在代码的不同部分定义,所以重要的是case语句在guard中或之前失败以使其他部分评估的函数(如果匹配失败,那就是).

// The incoming request
case class Req(path: List[String], requestType: Int)

// Does some heavy database action (not shown here)
def findInDb(req: Req):Option[Int] = 
  if(req.path.length > 3) Some(2) else None

Req("a"::"b"::Nil, 3) match {
  case r@Req(`path` :: _ :: Nil, 3) if findInDb(r).isDefined =>
    doSomethingWith(findInDb(r))
  case r@Req(`path` :: _ :: Nil, _) => doDefault
  case _ => doNothing
}
Run Code Online (Sandbox Code Playgroud)

现在,为了知道case语句成功,我必须查询数据库findInDb并检查结果是否有效.之后,我必须再次调用它来使用该值.

做点什么

case r@Req(path, 3) if {val res = findInDb(r); res.isDefined} =>
Run Code Online (Sandbox Code Playgroud)

不起作用,因为范围res仅限于括号内.

我当然可以定义一个var res = _外部并分配给它,但我感觉不太好.

是否有可能在守卫内声明一个变量?如果有可能case r@Req(…)为什么不case r@Req() if res@(r.isDefined)呢?

Dav*_*ith 9

你其实很亲密.缺少的关键部分是使用提取器而不是保护表达式.

object FindInDb{
   def unapply(r:Req):Option[Int]= findInDb(r)    
}

Req("a"::"b"::Nil, 3) match {
  case dbResult@FindInDb(Req(`path` :: _ :: Nil, 3))=> doSomethingWith(dbResult)
  case Req(`path` :: _ :: Nil, _) => doDefault
  case _ => doNothing
}
Run Code Online (Sandbox Code Playgroud)

实际上并不要求提取器只返回其参数中已存在的信息,这只是常见的用例.您实际上可以使用任何部分函数,​​将其提升为Option,并且能够匹配有关函数是否已定义及其值的信息.


Ran*_*ulz 0

你试过了吗case r @ Req() if res@(r.isDefined)

scala> val t3 =(1, "one", 1.0)
t3: (Int, java.lang.String, Double) = (1,one,1.0)

scala> t3 match { case t @ (1, s, d) if t._3 < 2.0 => println("OK"); case _ => println("No-Go") }
OK
Run Code Online (Sandbox Code Playgroud)