我发现很遗憾我无法从如此简单的结构中返回返回值 try ... catch ... finally
def foo: String = {
val in = new BufferedReader(.....)
try {
// val in = new BufferedReader(.....) -- doesn't matter
in.readLine
}
catch {
case e: IOException => e.printStackTrace()
}
finally {
in.close()
}
}
Run Code Online (Sandbox Code Playgroud)
此代码无法编译.有没有办法让编译期望使用任何库,高级结构等?我只想通过使用纯Scala作为编程语言的能力来做到这一点.
Tox*_*rog 40
在scala try-catch-finally块中,仅针对副作用finally评估块; 整个块的值是(如果没有抛出异常)或(如果有的话)中的最后一个表达式的值.trycatch
如果你查看编译器的输出,你会注意到它抱怨catch块的内容,而不是finally:
$ scala test.scala
/tmp/test.scala:12: error: type mismatch;
found : Unit
required: String
case e: Exception => e.printStackTrace()
Run Code Online (Sandbox Code Playgroud)
这是因为Exception.printStackTrace()回报Unit,因此函数的返回类型必须是String如果try成功,Unit否则.
您可以通过将catch块计算为String 来解决此问题:
catch {
case e: IOException => {
e.printStackTrace()
e.toString()
}
}
Run Code Online (Sandbox Code Playgroud)
当然,这意味着即使发生错误,也可以返回一些有用的字符串值(也许""?); 更惯用的方法可能是返回一个Option[String],try块返回Some(in.readLine)并catch返回块None.但是,在任何一种情况下,try和catch块的值必须与函数签名匹配.该finally模块的类型无关.
作为参考,这是一个通过类型检查和工作的版本:
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.IOException
def foo: String = {
val in = new BufferedReader(new InputStreamReader(System.in))
try {
in.readLine
}
catch {
case e: IOException => { e.printStackTrace(); e.toString() }
}
finally {
in.close()
}
}
System.out.println("Return value: " + foo)
Run Code Online (Sandbox Code Playgroud)
in.close()返回Unit,但没关系,因为finally忽略了块的值.在try和catch块都返回字符串.
Ale*_*lex 14
我认为从一个例外的Java概念开始会有所帮助.如果调用它,Java方法基本上是做某事(返回值或引起副作用)的契约.该方法做出某些假设(例如,操作系统将与读取文件的请求合作).有时,如果不满足这些条件,它将返回一个空值,有时它将完全停止执行并"抛出异常".
这可能是一个问题,因为Java方法的契约并不总是很清楚.声明返回类型为String的Java方法实际上有三个结果:String值,null或异常.异常的一个问题是它们停止执行代码,可能会掩盖方法中的其他问题,或者可能无法关闭已打开的资源(这是原因try, catch, finally)
Scala寻求关于返回类型的清晰度.一种方法是收集方法中出现的所有异常,然后将该异常列表作为返回值传递.但是,我们需要有一个返回类型,说"我们要返回一些东西,或者我们可能什么都不返回"(scala.Option),或者说,"我们将返回预期的答案或我们" ll将返回有关未返回预期答案的原因的信息"(scala.util.Either),或者可能是"我们将尝试进行有风险的操作,这可能会导致成功或失败." (scala.util.Try)
Scala使用Option处理null值的可能性.Option是具有两个子类的类:None和Some,它是一个只包含一个元素的容器.例如:
val contacts = Map("mark" -> 1235551212, "john" -> 2345551212, "william" -> 3455551212)
val phoneOfJohn: Option[Int] = contacts.get("john")
val phoneOfAlex: Option[Int] = contacts.get("alex")
phoneOfJohn match {
case Some(number) => callPhone(number)
case None => Logger.debug("unable to call John, can't find him in contacts")
}
phoneOfAlex match {
case Some(number) => callPhone(number)
case None => Logger.debug("unable to call Alex, can't find him in contacts")
}
Run Code Online (Sandbox Code Playgroud)
这个代码打电话给约翰,它会记录它无法打电话给Alex的事实,因为它无法在电话簿中找到他的电话号码.但是,a Option不提供有关没有返回任何值的原因的信息.如果我们想收集这些原因,我们可以使用Either.它Either有两个子类:A Left可以存储在执行"危险操作"过程中收集的所有异常,而a Right类似于a Some并包含期望值.
在Either上执行折叠操作以将其转换为Left或Right有点违反直觉,因此我们来到scala.util.Try.
@marius是Twitter的scala开发人员,他写了一篇关于采用scala.util.Try的理由的非常好的帖子.我想这就是你要找的东西.
scala.util.Try的本质是冒险行为会导致Success或Failure.在scala.util.Try之前,开发人员将使用Option或Either.如果您从文件中执行缓冲读取器,它会是什么样子:
import scala.util.{Try, Failure, Success}
def foo(fileName: String): Try[String] = Try {
scala.io.Source.fromFile(fileName).bufferedReader().readLine()
}
def bar(file: String): Unit = foo(file) match {
case Success(answer) => Logger.info(s"$file says the answer is $answer")
case Failure(e) => Logger.error(s"couldn't get answer, errors: ${e.getStackTrace}")
}
bar("answer.txt") \\ will log the answer or a stack trace
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
33852 次 |
| 最近记录: |