未初始化的变量(块不能包含声明)

时间:2018-08-03 09:02:58

标签: scala object variables

下面是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的初学者,所以我在这里有点迷茫。

1 个答案:

答案 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