Scala local return?

I just found that return in the next closure will return from the findPackage function

 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 } 

Can I somehow make a local answer, please? Thanks.

+4
source share
4 answers

Or you can get rid of your cycle and replace it with what you are trying to do: β€œfind”

 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 } 
+10
source

I fully support James Irie's suggestion, but for the sake of demonstration:

 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 } 

What changed?

I added a try{} block around the body of the anonymous function, and then the catch expression at the end looks for scala.runtime.NonLocalReturnControl exception, then I extract and pass the return value.

Why does it work?

Returning from a nested anonymous function throws a scala.runtime.NonLocalReturnControl exception, which is caught by the host function or method.

Scala Language Specification , Section 6.20. Return Expressions:

... The return from the nested anonymous function is thrown and caught by scala.runtime.NonLocalReturnException. Any exception delayed between the return point and the enclosing methods may see the exception. A key comparison ensures that these exceptions are caught only by the method instance, which is completed by the return.

If the return statement itself is part of an anonymous function, it is possible that the environment instance f has already returned before executing the return statement. In this case, the thrown scala.runtime.NonLocalReturnException will not be caught and will distribute the call stack.

+8
source

Yes, you can define a local method:

 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 } 

or by throwing some kind of exception and catching it:

 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 } 
+4
source

I had a similar problem and solved it by distributing any ControlThrowable that I could find, for example, 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)) } } 

Note that in this case, simply deleting the "return" statement solves the problem ...

0
source

Source: https://habr.com/ru/post/949660/


All Articles