如何在 Scala 中使用参数化特征的反射?

发布于 2024-11-27 08:45:11 字数 1069 浏览 1 评论 0原文

由于 scala 中的一个特性,对 Manifest 的访问似乎很棘手。

这段代码如何在 scala 中编译?

trait SomeTraitOf[+A] {

  def newInstanceOfA : A = /*  necessary code to make it work */

}

(相关,它作为参数化类工作得很好:

class SomeTraitOf[A : Manifest] {

  def newInstanceOfA(implicit m : Manifest[A]) : A =
     m.erasure.newInstance.asInstanceOf[A] 

}

但不能使用协变类型参数(+A))

编辑:真正的东西

sealed trait RootPeerProxy[+A] extends Proxy {

  def peer: A
  def self = peer
  def peerManifest[B >: A](): Option[Manifest[B]]
  private[scalavaadin] def newInstance() : Option[A]
}

trait PeerProxy[+A] extends RootPeerProxy[A] {
  override def peerManifest[B >: A](): Option[Manifest[B]]
  override def peer(): A = this.newInstance match {
    case None => {throw new IllegalStateException("oups")} 
    case Some(a) => a
  }
  private[scalavaadin] override def newInstance() : Option[A] = peerManifest map { m =>    m.erasure.newInstance.asInstanceOf[A] }
}

由于特征无法为参数化特征提供清单,所以实现该特征的类应该,但我没有得到它。

The access on Manifest seems to be tricky from a trait in scala.

How could this code compile in scala ?

trait SomeTraitOf[+A] {

  def newInstanceOfA : A = /*  necessary code to make it work */

}

(Related, it works fine as a parametized class :

class SomeTraitOf[A : Manifest] {

  def newInstanceOfA(implicit m : Manifest[A]) : A =
     m.erasure.newInstance.asInstanceOf[A] 

}

but not with a covariant type parameter (+A))

Edit : The real stuff

sealed trait RootPeerProxy[+A] extends Proxy {

  def peer: A
  def self = peer
  def peerManifest[B >: A](): Option[Manifest[B]]
  private[scalavaadin] def newInstance() : Option[A]
}

trait PeerProxy[+A] extends RootPeerProxy[A] {
  override def peerManifest[B >: A](): Option[Manifest[B]]
  override def peer(): A = this.newInstance match {
    case None => {throw new IllegalStateException("oups")} 
    case Some(a) => a
  }
  private[scalavaadin] override def newInstance() : Option[A] = peerManifest map { m =>    m.erasure.newInstance.asInstanceOf[A] }
}

Since traits cannot provide manifest for the parametized trait, the class implementing the trait should, but I am not getting it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

中二柚 2024-12-04 08:45:11

关于协方差

由于Manifest[A]在参数A中是不变的,所以你不能直接做你想做的事情。通常的策略是弱化返回类型,

trait SomeTraitOf[+A] {
  def newInstance[B >: A](implicit m: Manifest[B]): B = {
    m.erasure.newInstance.asInstanceOf[B]
  }
}

您可以使用如下特征,

class Parent
class Child extends Parent
val childBuilder = new SomeTraitOf[Child] {}
val parentBuilder: SomeTraitOf[Parent] = childBuilder
parentBuilder.newInstance // returns a Parent!

关于视图边界

从下面的评论中,我猜您也在问“视图边界”,这只是声明隐式参数的简洁方法。您的声明

class SomeTraitOf[A : Manifest] { ...

基本上转化为

class SomeTraitOf[A]()(implicit m0: Manifest[A]) { ....

Traits 不能有视图边界,因为它们不能接受任何(值)参数。但这在这里并不是真正的问题,因为在您的示例中

class SomeTraitOf[A : Manifest] {
  def newInstanceOfA(implicit m : Manifest[A]) : A =
     m.erasure.newInstance.asInstanceOf[A] 
}

您没有使用视图绑定! (您正在使用参数m。)如果您想使用视图绑定,您可以这样做:

class SomeTraitOf[A : Manifest] {
  def newInstanceOfA : A =
     implicitly[Manifest[A]].erasure.newInstance.asInstanceOf[A] 
}

About covariance:

Since Manifest[A] is invariant in the parameter A, you can't do what you want directly. The usual strategy is to weaken the return type,

trait SomeTraitOf[+A] {
  def newInstance[B >: A](implicit m: Manifest[B]): B = {
    m.erasure.newInstance.asInstanceOf[B]
  }
}

You can use the trait as follows,

class Parent
class Child extends Parent
val childBuilder = new SomeTraitOf[Child] {}
val parentBuilder: SomeTraitOf[Parent] = childBuilder
parentBuilder.newInstance // returns a Parent!

About View Bounds:

From your comment below, I guess you're also asking about "view bounds", which are just a concise way of declaring an implicit parameter. Your declaration

class SomeTraitOf[A : Manifest] { ...

basically translates to

class SomeTraitOf[A]()(implicit m0: Manifest[A]) { ....

Traits can't have view bounds because they can't take any (value) parameters. But that's not really a problem here, because in your example

class SomeTraitOf[A : Manifest] {
  def newInstanceOfA(implicit m : Manifest[A]) : A =
     m.erasure.newInstance.asInstanceOf[A] 
}

you're not using the view bound! (You're using the parameter m instead.) If you wanted to use the view bound, you could do it this way:

class SomeTraitOf[A : Manifest] {
  def newInstanceOfA : A =
     implicitly[Manifest[A]].erasure.newInstance.asInstanceOf[A] 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文