在即将到来的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
? 是不是应该使异常处理在斯卡拉看起来像其他一些语言 (如果是的话,哪一个)一个DSL?
有思考例外两种方式。 一种方法是把它们作为流量控制:一个异常改变程序的执行流程,使得从一个地方执行跳转到另一个。 第二种方式是把它们作为数据:一个例外是关于程序,其然后可以被用作输入到程序的其他部分的执行的信息。
在try
/ catch
在C ++和Java使用模式是非常多的第一类(*)的。
但是,如果您更愿意处理异常的数据,那么你就必须诉诸如图所示的一个代码,。 对于简单的情况下,这是相当容易的。 然而,当涉及到功能性的风格,其中成分为王,事情开始变得复杂。 你要么不得不各地复制代码,或者你滚你自己的库来处理它。
因此,其意是支持的功能和风格OO语言,人们不应该感到惊讶地看到治疗的异常数据库支持。
另请注意,是提供哦,所以,许多其他的可能性Exception
处理事情。 你可以,例如,链catch处理器,在很多的方式,升降链的部分功能,可以很容易地委派对网页请求的处理责任。
这里是什么可以做一个例子,因为自动资源管理盛行,这些天:
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
收到一个通用的可关闭的,但我需要一个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))
有趣的是在这里, 我完全解耦的异常处理 (该catch
的一部分try
/ catch
从资源 ,这是通过做闭幕 ) finally
。 此外,错误处理是一个值我可以传递给函数。 最起码,它使嘲讽try
/ catch
/ finally
语句容易得多。 :-)
另外,我可以组合多种Catch
使用or
方法,所以我的代码,不同的层可以选择不同的异常添加不同的处理程序。 这确实是我的主要观点,但我无法找到一个异常丰富的界面(在短暂的时间我看了:)。
我将与有关的定义的话结束arm
我给了。 这不是一个好。 特别是,我不能使用Catch
方法,如toEither
或toOption
到结果,从改变R
别的东西,这严重降低了使用的价值Catch
它。 我不知道如何去改变,虽然。
至于谁写的家伙,原因是组成和封装。 Scala编译器(和我打赌最体面的大小源基地)中充斥着这吞下所有异常的地方 - 你可以看到这些与-Ywarn渔获物 - 因为程序员是懒得列举相关的,这是可以理解的因为这很烦人。 由于能够定义,再利用,并撰写渔获物和finally块独立的试逻辑的,我希望能降低屏障写明智块。
而且,它不完全完成,我正在上万元的其他领域了。 如果你通过演员的代码,你可以看到巨大的剪切和粘贴的多重嵌套的try / catch / finally块的例子。 我/我不愿满足于try { catch { try { catch { try { catch ...
我的最终计划是拥有捕捞采取实际PartialFunction
,而不是需要case语句的文字列表,其中介绍的机会的一个全新的水平,即try foo() catch getPF()
我会说这是最重要的表达风格问题。
除了比它的等效短,新捕()方法提供表达相同的行为一个功能更强大的方式。 尝试... catch语句通常被认为是势在必行的风格和异常被认为是副作用。 捕()把毯子铺在这个命令性代码从视图中隐藏。
更重要的是,现在我们有一个功能,那么它可以与其他的东西可以更容易地组成; 它可以被传递到其他高阶函数来创建更复杂的行为。 (你不能传递一个try ... catch语句具有参数化异常直接输入)。
看看这另一种方式是,如果斯卡拉没有提供这个醒目()函数。 那么最有可能的人将独立“重新发明”它,这会导致重复代码,并导致更多的非标码。 所以我觉得斯卡拉设计师认为这个功能是很常见,以保证它包括在标准Scala库。 (并且我同意)
亚历克斯