scala 2.8控制异常 - 有什么意义? [英] scala 2.8 control Exception - what is the point?

查看:79
本文介绍了scala 2.8控制异常 - 有什么意义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在即将到来的scala 2.8中,添加了一个 util.control 包,其中包含一个中断库和一个用于处理异常的构造,以使代码看起来像: p>

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

可以用以下代码替换:

  import util.control.Exception._ 
val maybeInt = catching(classOf [NFE])opt arg.toInt
/ pre>

我的问题是为什么?这是什么添加到语言,而不是提供另一种(和根本不同的)表达方式事情?有没有什么可以使用新的控件表达,但不能通过 try-catch ?它是一个DSL应该使Scala中的异常处理看起来像其他语言(如果是,哪一个)?

解决方案

有两种方法来考虑异常。一种方法是将它们视为流量控制:一个异常会改变程序的执行流程,使执行从一个地方跳到另一个地方。第二种方法是将它们视为数据:异常是关于程序执行的信息,然后可以将其用作程序其他部分的输入。



C ++和Java中使用的 c catch paradigm是第一种(*)。



但是,如果您希望将异常作为数据处理,则必须使用所显示的代码。对于简单的情况,这很简单。然而,当涉及组合是国王的功能风格时,事情开始变得复杂。您或者必须复制代码,或者滚动自己的库来处理它。



因此,在一种旨在支持功能和OO风格的语言中,不要惊讶地看到图书馆支持将例外处理为数据。



请注意,有$ - code提供的许多其他可能性>例外来处理事物。例如,您可以使用链接捕获处理程序,其方式与Lift链部分功能相一致,以便轻松地将责任委托给处理网页请求。



这里这是一个可以做的事情的例子,因为自动资源管理现在很流行:

  def arm [T: java.io.Closeable,R](resource:T)(body:T => R)(处理程序:Catch [R]):R =(
处理程序
和最后(忽略(classOf [ ]){resource.close()})
申请单位(资源)

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



(*)奇怪的是,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格式(lineNumber,lineText))
lineText = lnr.readLine()
}
lineNumber
} _
pre>

这是这个函数的类型:

  linePrinter: (lnr:java.io.LineNumberReader)(util.control.Exception.Catch [Int])=> Int 

所以, arm 收到一个通用的关闭,但我需要一个LineNumberReader,所以当我调用这个函数我需要传递。然而,我返回的是一个函数 Catch [Int] => Int ,这意味着我需要将两个参数传递给 linePrinter 以使其正常工作。现在我们来看一下读者

  val functionText = def linePrinter(lnr:java.io.LineNumberReader)= arm(lnr){lnr => 
var lineNumber = 1
var lineText = lnr.readLine()
while(null != lineText){
println(%4d:%sformat(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格式(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:流关闭

现在假设如果发生异常,我想返回0。我可以这样做:

  linePrinter(new java.io.LineNumberReader(reader))(allCatch withApply(_ => ; 0))

有趣的是,我完全解除了异常处理( catch 部分 try / catch )<从资源关闭 /> c $ c>完成。此外,错误处理是一个可以传递给该函数的值。至少,它使嘲笑尝试 / catch / finally 语句更容易。 : - )



此外,我可以使用 Catch c $ c>方法,以便我的代码的不同层可能会选择为不同的异常添加不同的处理程序。这真的是我的主要观点,但是我找不到异常丰富的界面(在短暂的时候我看到了)。



我会完成一个评论关于我给出的 arm 的定义。这不是一个好的特别是,我不能使用 Catch 方法,例如 toEither toOption 将结果从 R 更改为其他内容,这严重降低了使用 Catch 的值。我不知道如何改变,但是。


In the upcoming scala 2.8, a util.control package has been added which includes a break library and a construct for handling exceptions so that code which looks like:

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

Can be replaced with code like:

import util.control.Exception._
val maybeInt = catching(classOf[NFE]) opt arg.toInt

My question is why? What does this add to the language other than providing another (and radically different) way to express the same thing? Is there anything which can be expressed using the new control but not via try-catch? Is it a DSL supposed to make exception-handling in Scala look like some other language (and if so, which one)?

解决方案

There are two ways to think about exceptions. One way is to think of them as flow control: an exception changes the flow of execution of the program, making the execution jump from one place to another. A second way is to think of them as data: an exception is an information about the execution of the program, which can then be used as input to other parts of the program.

The try/catch paradigm used in C++ and Java is very much of the first kind(*).

If, however, if you prefer to deal with exceptions as data, then you'll have to resort to code such as the one shown. For the simple case, that's rather easy. However, when it comes to the functional style where composition is king, things start to get complicated. You either have to duplicate code all around, or you roll your own library to deal with it.

Therefore, in a language which purports to support both functional and OO style, one shouldn't be surprised to see library support for treating exceptions as data.

And note that there is oh-so-many other possibilities provided by Exception to handle things. You can, for instance, chain catch handlers, much in the way that Lift chain partial functions to make it easy to delegate responsibility over the handling of web page requests.

Here is one example of what can be done, since automatic resource management is in vogue these days:

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)
)

Which gives you a safe closing of the resource (note the use of ignoring), and still applies any catching logic you may want to use.

(*) Curiously, Forth's exception control, catch&throw, is a mix of them. The flow jumps from throw to catch, but then that information is treated as data.

EDIT

Ok, ok, I yield. I'll give an example. ONE example, and that's it! I hope this isn't too contrived, but there's no way around it. This kind of thing would be most useful in large frameworks, not in small samples.

At any rate, let's first define something to do with the resource. I decided on printing lines and returning the number of lines printed, and here is the code:

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
} _

Here is the type of this function:

linePrinter: (lnr: java.io.LineNumberReader)(util.control.Exception.Catch[Int]) => Int

So, arm received a generic Closeable, but I need a LineNumberReader, so when I call this function I need to pass that. What I return, however, is a function Catch[Int] => Int, which means I need to pass two parameters to linePrinter to get it to work. Let's come up with a Reader, now:

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))

So, now, let's use it. First, a simple example:

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

And if I try it again, I get this:

scala> linePrinter(new java.io.LineNumberReader(reader))(noCatch)
java.io.IOException: Stream closed

Now suppose I want to return 0 if any exception happens. I can do it like this:

linePrinter(new java.io.LineNumberReader(reader))(allCatch withApply (_ => 0))

What's interesting here is that I completely decoupled the exception handling (the catch part of try/catch) from the closing of the resource, which is done through finally. Also, the error handling is a value I can pass on to the function. At the very least, it makes mocking of try/catch/finally statements much easier. :-)

Also, I can combine multiple Catch using the or method, so that different layers of my code might choose to add different handlers for different exceptions. Which really is my main point, but I couldn't find an exception-rich interface (in the brief time I looked :).

I'll finish with a remark about the definition of arm I gave. It is not a good one. Particularly, I can't use Catch methods such as toEither or toOption to change the result from R to something else, which seriously decreases the value of using Catch in it. I'm not sure how to go about changing that, though.

这篇关于scala 2.8控制异常 - 有什么意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆