gpt4 book ai didi

scala 2.8 控制异常 - 有什么意义?

转载 作者:行者123 更新时间:2023-12-03 11:49:51 26 4
gpt4 key购买 nike

在即将到来的 scala 2.8 中,util.control添加了一个包,其中包括一个中断库和一个用于处理异常的构造,因此代码如下所示:

type NFE = NumberFormatException
val arg = "1"
val maybeInt = try { Some(arg.toInt) } catch { case e: NFE => None }

可以用如下代码替换:
import util.control.Exception._
val maybeInt = catching(classOf[NFE]) opt arg.toInt

我的问题是为什么?除了提供另一种(并且完全不同的)方式来表达同一事物之外,这对语言有什么好处?有什么可以使用新控件表达但不能通过 try-catch 表达的东西吗? ?它是否应该使 Scala 中的异常处理看起来像其他语言(如果是,是哪一种)?

最佳答案

有两种方法可以考虑异常。一种方法是将它们视为流控制:异常会改变程序的执行流程,使执行从一个地方跳到另一个地方。第二种方法是将它们视为数据:异常是有关程序执行的信息,然后可以将其用作程序其他部分的输入。
try/catch C++ 和 Java 中使用的范式非常属于第一类(*)。

但是,如果您更愿意将异常作为数据处理,那么您将不得不求助于所示的代码。对于简单的情况,这很容易。然而,当谈到以组合为王的功能风格时,事情开始变得复杂起来。您要么必须到处复制代码,要么使用自己的库来处理它。

因此,在一种声称支持函数式和 OO 风格的语言中,看到库支持将异常视为数据时,我们应该不会感到惊讶。

请注意,Exception 提供了许多其他可能性。处理事情。例如,您可以使用链式捕获处理程序,就像 Lift 链的部分功能一样,可以轻松地委派处理网页请求的责任。

这是可以做的一个示例,因为这些天自动资源管理很流行:

def arm[T <: java.io.Closeable,R](resource: T)(body: T => R)(handlers: Catch[R]):R = (
handlers
andFinally (ignoring(classOf[Any]) { resource.close() })
apply body(resource)
)

这使您可以安全地关闭资源(注意使用忽略),并且仍然应用您可能想要使用的任何捕获逻辑。

(*) 奇怪的是,Forth 的异常控制, catch & throw , 是它们的混合体。流量从 throw 跳转至 catch ,但随后该信息被视为数据。

编辑

好吧,好吧,我屈服了。我举个例子。一个例子,就是这样!我希望这不是太做作,但没有办法解决它。这种东西在大型框架中最有用,而不是在小样本中。

无论如何,让我们首先定义一些与资源有关的东西。我决定打印行并返回打印的行数,代码如下:
def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =>
var lineNumber = 0
var lineText = lnr.readLine()
while (null != lineText) {
lineNumber += 1
println("%4d: %s" format (lineNumber, lineText))
lineText = lnr.readLine()
}
lineNumber
} _

这是此函数的类型:
linePrinter: (lnr: java.io.LineNumberReader)(util.control.Exception.Catch[Int]) => Int

所以, arm收到了一个通用的 Closeable,但我需要一个 LineNumberReader,所以当我调用这个函数时,我需要传递它。然而,我返回的是一个函数 Catch[Int] => Int ,这意味着我需要将两个参数传递给 linePrinter让它工作。让我们想出一个 Reader , 现在:
val functionText = """def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =>
var lineNumber = 1
var lineText = lnr.readLine()
while (null != lineText) {
println("%4d: %s" format (lineNumber, lineText))
lineNumber += 1
lineText = lnr.readLine()
}
lineNumber
} _"""

val reader = new java.io.LineNumberReader(new java.io.StringReader(functionText))

所以,现在,让我们使用它。首先,一个简单的例子:
scala> linePrinter(new java.io.LineNumberReader(reader))(noCatch)
1: def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =>
2: var lineNumber = 1
3: var lineText = lnr.readLine()
4: while (null != lineText) {
5: println("%4d: %s" format (lineNumber, lineText))
6: lineNumber += 1
7: lineText = lnr.readLine()
8: }
9: lineNumber
10: } _
res6: Int = 10

如果我再试一次,我会得到:
scala> linePrinter(new java.io.LineNumberReader(reader))(noCatch)
java.io.IOException: Stream closed

现在假设如果发生任何异常,我想返回 0。我可以这样做:
linePrinter(new java.io.LineNumberReader(reader))(allCatch withApply (_ => 0))

这里有趣的是 我完全解耦了异常处理 ( catchtry/ catch 的一部分) 从资源关闭 ,这是通过 finally 完成的.此外,错误处理是我可以传递给函数的值。至少,它 mock 了 try。/ catch/ finally陈述要容易得多。 :-)

另外,我可以组合多个 Catch使用 or方法,以便我的代码的不同层可能会选择为不同的异常添加不同的处理程序。这确实是我的主要观点,但我找不到一个异常丰富的界面(在我看了很短的时间内:)。

最后,我将对 arm 的定义发表评论。我给了。这不是一个好的。特别是,我不能使用 Catch方法如 toEithertoOptionR 更改结果到别的东西,这严重降低了使用 Catch 的值(value)在里面。不过,我不确定如何改变这一点。

关于scala 2.8 控制异常 - 有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1644813/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com