Generics Scala-我该如何做一个;资产抛出;方法?

Generics Scala-我该如何做一个;资产抛出;方法?,generics,scala,Generics,Scala,我昨天开始学习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

我昨天开始学习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
    。无论我做什么,我都会得到一个预期的
    类类型,但E发现了错误
  • 如果我从最后一行中删除E(例如,将其替换为抛出新的断言错误(“预期错误”)),我会得到这样的结果:
    警告:类型模式中的抽象类型E未选中,因为它已通过擦除被消除
我认为我遇到的两个问题与Scala(可能还有java)处理抽象类型的方式以及它们是如何完成的有关

如何修复我的资产


优点:我指定“块类型”(
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 )
}

感谢您向我展示了如何做到这一点。

多亏了肯的回答,我才使这件事起作用:

class AssertException(msg: String) extends Exception(msg: String)

def assertThrows[E](f: => Unit)(implicit eType:ClassManifest[E]) {
  try{
    f
  } catch {
  case e: Exception =>
    if(eType.erasure.isAssignableFrom(e.getClass)) { return }
  }
  throw new AssertException("Expected error of type " + eType.erasure.getName )
}

/* examples of usage */

assertThrows[NullPointerException]{ throw new NullPointerException() } // ok
assertThrows[AssertException] { assertThrows[Exception]{ } } // ok!

非常感谢

不久前我提出的一个问题可能会有所帮助:谢谢你的回答。你能举一个使用的例子吗?我不能让它工作。没关系,我让它工作了(补充了一个答案)。我正在编辑你答案中的一个小错误,并将其标记为正确。