我昨天开始学习Scala,所以我很陌生。学习一种新语言时,我喜欢做的一件事就是尝试创建一个微型TDD库。

这是我到目前为止所得到的:

def assert(condition: Boolean, message: String) {
  if(!condition){ throw new AssertionError(message) }
}

def assertThrows[E](f: => Unit) {
  try {
    f
  } catch {
    case e: E => { return }
    case _: Exception => { }
  }
  throw new AssertionError("Expected error of type " + classOf[E] )
}


assert的代码工作正常,但是assertThrows存在两个问题。


看来我无法在最后一行使用E。无论我做什么,我都会得到一个class type expected but E found error
如果我从最后一行删除E(例如,用throw new AssertionError("error expected")替换它),则会得到以下信息:warning: abstract type E in type pattern is unchecked since it is eliminated by erasure


我认为我遇到的两个问题与Scala(可能还有Java)处理抽象类型的方式有关,以及它们是如何完成的。

如何修复assertThrows?

优点:我指定“块类型”(f: => Unit)的方式正确吗?

最佳答案

Java虚拟机通过类型擦除实现泛型,因此JVM在方法主体内部实际上不了解E类型是什么,因此该AssertThrows方法无法按您希望的方式工作。您需要为异常类隐式传递一个清单,如下所示:

def assertThrows[E](f: => Unit)(implicit eType:ClassManifest[E]) {


然后,您可以在主体中使用它来捕获异常或获取类名,如下所示:

  try {
    f
  } catch {
    case e: Exception =>
      if ( eType.erasure.isAssignableFrom(e.getClass))
        return;
  }
  throw new AssertionError("Expected error of type " + eType.erasure.getName )
}


感谢the Spring framework's AssertThrows class向我展示了如何执行此操作。

10-08 12:39