Скала местное возвращение? - PullRequest
4 голосов
/ 14 марта 2012

Я только что обнаружил, что return s в следующем закрытии вернется из функции 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
}

Могу ли я как-нибудь сделать локальный возврат, пожалуйста? Спасибо.

Ответы [ 4 ]

10 голосов
/ 14 марта 2012

Или вы можете избавиться от цикла и заменить его тем, что вы пытаетесь сделать: «найти»

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
}
8 голосов
/ 14 марта 2012

Я полностью поддерживаю предложение Джеймса Ири, но ради демонстрации:

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 , раздел 6.20 Выражения возврата:

... Возврат из вложенной анонимной функции осуществляется путем генерирования и перехвата исключения scala.runtime.NonLocalReturnException.Любое исключение, пойманное между точкой возврата и включающими методами, может увидеть исключение.Сравнение ключей гарантирует, что эти исключения перехватываются только экземпляром метода, который завершается возвратом.

Если возвращаемое выражение само является частью анонимной функции, возможно, что вмещающий экземпляр f имеетуже возвращено до выполнения выражения возврата.В этом случае выброшенное исключение scala.runtime.NonLocalReturnException не будет перехвачено и будет распространяться вверх по стеку вызовов.

4 голосов
/ 14 марта 2012

Да, вы можете, определив локальный метод:

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
}
0 голосов
/ 07 июня 2012

У меня была похожая проблема, и я решил ее, распространяя любой ControlThrowable, который я могу найти, как он говорит здесь

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 "решает проблему ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...