【问题标题】:Scala local return?Scala 本地返回?
【发布时间】:2012-03-31 05:19:39
【问题描述】:

我刚刚发现returns 在下面的闭包中会从函数findPackage返回

def findPackage(name: String, suffix: Option[String] = None): Path = {
    logger.debug("Looking for package {} with suffix {}", name, suffix)
    val path: Path = using(Files.newDirectoryStream(appDir)) {dirs =>
        for (val path <- dirs) {
            val matcher = packagePattern.matcher(path.getFileName.toString)
            if (matcher.matches() && matcher.group(1).equals(name))
                if (suffix.isDefined) {
                    if (matcher.group(2) != null && matcher.group(2).equals(suffix.get))
                        return path
                } else
                    return path
        }
        throw new PackageNotFoundException(this, name, suffix)
    }
    logger.debug("Found package is {}", path)
    path
}

我可以以某种方式进行 local 退货吗?谢谢。

【问题讨论】:

    标签: scala controls closures


    【解决方案1】:

    我遇到了类似的问题,我通过传播我可能找到的任何 ControlThrowable 解决了它,就像它说的 here

    def asJson: JsValue = {
      val key = "classification.ws.endpoint"
    
      configuration.getString(key).map{ url =>
        try {
          return WS.url(url).get().await.get.json
        } catch {
          case ce : scala.util.control.ControlThrowable => throw ce
          case e => throw InvalidWebServiceResponseException("Error accessing '%s'".format(url), e)
        }
      }.getOrElse {
        throw new MissingConfigurationException("No value found for '%s' configuration".format(key))
      }
    
    }
    

    请注意,在这种情况下,只需删除“return”语句即可解决问题...

    【讨论】:

      【解决方案2】:

      我完全支持 James Iry 的建议,但为了演示:

      def findPackage(name: String, suffix: Option[String] = None): Path = {
          logger.debug("Looking for package {} with suffix {}", name, suffix)
          val path: Path = using(Files.newDirectoryStream(appDir)) {dirs =>
              try {
                for (val path <- dirs) {
                    val matcher = packagePattern.matcher(path.getFileName.toString)
                    if (matcher.matches() && matcher.group(1).equals(name))
                        if (suffix.isDefined) {
                            if (matcher.group(2) != null && matcher.group(2).equals(suffix.get))
                                return path
                        } else
                           return path
                }
                throw new PackageNotFoundException(this, name, suffix)
              } catch { case e:scala.runtime.NonLocalReturnControl[Path] => e.value}
          }
          logger.debug("Found package is {}", path)
          path
      }
      

      发生了什么变化?

      我在匿名函数的主体周围添加了一个try{} 块,然后在末尾添加catch 表达式以查找scala.runtime.NonLocalReturnControl 异常,然后提取并传递返回值。

      为什么有效?

      从嵌套匿名函数返回引发scala.runtime.NonLocalReturnControl 异常,该异常被宿主函数或方法捕获。

      Scala Language Spec,第 6.20 节返回表达式:

      ... 从嵌套匿名函数返回由以下方式实现 抛出并捕获 scala.runtime.NonLocalReturnException。任何 返回点和封闭点之间的异常捕获 方法可能会看到异常。一个关键的比较确保 这些异常只被方法实例捕获,它是 由返回终止。

      如果返回表达式本身是匿名函数的一部分,它 f 的封闭实例可能已经返回 在执行返回表达式之前。在这种情况下,抛出 scala.runtime.NonLocalReturnException 不会被捕获,并且会 向上传播调用堆栈。

      【讨论】:

        【解决方案3】:

        或者您可以摆脱循环并将其替换为您正在尝试执行的操作:“查找”

        def findPackage(name: String, suffix: Option[String] = None): Path = {
            logger.debug("Looking for package {} with suffix {}", name, suffix)
        
            def matching(path : Path) : Boolean = {
                val matcher = packagePattern.matcher(path.getFileName.toString)
                matcher.matches && matcher.group(1).equals(name) && (!suffix.isDefined || (matcher.group(2) != null && matcher.group(2).equals(suffix.get))
            }
        
            val path: Path = using(Files.newDirectoryStream(appDir)) {dirs =>
               dirs find matching getOrElse {throw new PackageNotFoundException(this, name, suffix)}
            }
        
            logger.debug("Found package is {}", path)
            path
        }
        

        【讨论】:

          【解决方案4】:

          是的,你可以,通过定义一个本地方法:

          def findPackage(name: String, suffix: Option[String] = None): Path = {
              logger.debug("Looking for package {} with suffix {}", name, suffix)
          
              def search(dirs: List[File]) = { // not sure what the type of dirs actually is
                  for (val path <- dirs) {
                      val matcher = packagePattern.matcher(path.getFileName.toString)
                      if (matcher.matches() && matcher.group(1).equals(name))
                          if (suffix.isDefined) {
                              if (matcher.group(2) != null && matcher.group(2).equals(suffix.get))
                                  return path
                          } else
                              return path
                  }
                  throw new PackageNotFoundException(this, name, suffix)
              }
          
              val path: Path = using(Files.newDirectoryStream(appDir))(search _)
              logger.debug("Found package is {}", path)
              path
          }
          

          或者通过抛出一些异常并捕获它:

          def findPackage(name: String, suffix: Option[String] = None): Path = {
              logger.debug("Looking for package {} with suffix {}", name, suffix)
              val path: Path = using(Files.newDirectoryStream(appDir)) {dirs =>
                  try {
                      for (val path <- dirs) {
                          val matcher = packagePattern.matcher(path.getFileName.toString)
                          if (matcher.matches() && matcher.group(1).equals(name))
                              if (suffix.isDefined) {
                                  if (matcher.group(2) != null && matcher.group(2).equals(suffix.get))
                                      throw new ReturnException(path)
                              } else
                                  throw new ReturnException(path)
                      }
                      throw new PackageNotFoundException(this, name, suffix)
                  }
                  catch { case ReturnException(path) => path }
              }
              logger.debug("Found package is {}", path)
              path
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-08-02
            • 1970-01-01
            • 2021-09-16
            • 2012-08-21
            • 2020-09-19
            • 2019-02-05
            • 2012-11-09
            相关资源
            最近更新 更多