下面是these examples,尤其是以下代码:
object Control {
def using[A <: { def close(): Unit }, B](resource: A)(f: A => B): B =
try {
f(resource)
} finally {
resource.close()
}
}
...
using(io.Source.fromFile("example.txt")) { source => { .....
我想扩展using
方法,因此它不是实现close
的类型,而是接收字符串(文件名),打开源的函数和处理函数。这样,如果给定文件不存在,我将避免在上面的示例中引发的异常。
所以我最终得到了这段代码:
object Control
{
def using[A <: { def close(): Unit }, B](opener: String => A)(name:String)(func: A => B): Unit =
{
var resource:A
// ^ Error: 'Block cannot contain declarations'
try
{
resource = opener(name)
func(resource)
}
catch
{
case e: (_) => println(s"Failed to open resource '${name}' (${e})")
}
finally
{
println("Closing file ...")
resource.close()
}
}
}
因此,我正在定义一个方法,该方法将opener
函数作为第一个参数,该函数接收一个字符串,并返回一个实现close
的字符串的对象(用于打开功能),和处理功能。
但是,它不允许我在resource
块之外声明try-catch
变量(因此我可以在finally
块中访问它)。如果我将其放入try
之类的var resource:A = opener(name)
块中,它将将起作用,但是然后我无法到达resource
块中的finally
。 / p>
我该如何解决?我不得不说我仍然是Scala的初学者,所以我在这里有点迷茫。
答案 0 :(得分:1)
这是一个修改后的示例,您也可以运行on Scastie:
import scala.util.control.NonFatal
import scala.language.reflectiveCalls
type Resource = { def close(): Unit }
def using[A <: Resource, B](opener: String => A)(name: String)(func: A => B): Unit = {
var resource = null.asInstanceOf[A]
try {
resource = opener(name)
func(resource)
} catch {
case NonFatal(e) => println(s"Failed to open resource '${name}' (${e.getMessage})")
} finally {
println("Closing resource...")
resource.close()
}
}
final class SomeKindOfResource(n: String) {
def use(): Int = n.toInt
def close(): Unit = {}
}
using(new SomeKindOfResource(_))("42")(n => println(n.use()))
using(new SomeKindOfResource(_))("NaN")(n => println(n.use()))
您缺少的是初始化:
var resource = null.asInstanceOf[A]
请注意,尽管您可能会认为,但这不会引发NullPointerException
。您可以详细了解here。
我添加了一些您可能感兴趣的东西:
明确导入scala.language.reflectiveCalls
:在运行时通过反射调用(至少在JVM上)实现结构化类型,并且编译器会在编译时告知您
将{ def close(): Unit }
命名为使用type
使用NonFatal
处理异常(您可以详细了解here)