Scala是否允许泛型对象的任意实例化?新的B {}?

时间:2019-01-24 04:38:01

标签: scala

我想知道这样的事情是否可以在Scala中实现:

def f[B <: AnyRef]()(implicit ct: ClassTag[B]): B = {
  new B {
    override def equals(o: Any) = ...
    override def hashcode(o: Any) = ...
  }
}

我的直觉是,即使使用ClassTag,也应该无法实例化任意B,因为我们不知道它甚至没有no-args参数。

但是我得到的实际错误是:

class type required but B found

我当前的用例是:我希望能够重新定义提供给我的任意对象的equals / hashcode(我无法逃避,因为我必须将这些对象传递给某些对象将使用这些对象的equals / hashcodes的错误框架,因此我对此无能为力)。 显而易见的方法是通过继承。有什么办法吗?

2 个答案:

答案 0 :(得分:5)

在一般情况下绝对不可能。

假设我为final传递了B类型,例如String。没有办法将其子类化。因此,您不能对任意B这样做。

根据其他框架的工作方式,您也许可以将其传递给AnyRef。否则,您也许可以使用宏完成一些工作,但是需要更多信息来确定这一点。

答案 1 :(得分:4)

Brian回答了标题中的问题(您也可以考虑B可以使用您不知道定义的抽象方法)。但是

  

我希望能够重新定义提供给我的任意对象的equals / hashcode

建议使用其他签名:

def f[B <: AnyRef](x: B): B = ...

,这一个 是可行的。当然有限制。如果B是接口,则可以使用dynamic proxies from Java standard library, 对于类,您需要一个CGLIB之类的库。大约(未试用):

def f[B <: AnyRef](x: B): B = {
  val enhancer = new Enhancer()
  enhancer.setSuperclass(x.getClass)
  val interceptor: MethodInterceptor = (obj, method, args, proxy) =>
    method.getName match {
      case "equals" => // your equals impl 
      case "hashCode" => // your hashCode impl 
      case _ => proxy.invokeSuper(obj, args)
    }
  enhancer.setCallback(interceptor)
  enhancer.create() as B
}