【问题标题】:How to use reflection on parameterized trait in Scala?如何在Scala中对参数化特征使用反射?
【发布时间】:2011-07-31 22:44:31
【问题描述】:

由于 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] }
}

由于特征不能为参数化特征提供清单,实现该特征的类应该,但我不明白。

【问题讨论】:

    标签: scala manifest traits


    【解决方案1】:

    关于协方差

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

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

    你可以像下面这样使用 trait,

    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]) { ....
    

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

    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] 
    }
    

    【讨论】:

    • class SomeTraitOf[+A : Manifest] { def newInstanceOfA[B >: A](implicit m : Manifest[B]) : B = m.erasure.newInstance.asInstanceOf[B] } 工作正常,但 trait 不携带清单信息。
    • 好的,我明白了,我不能像def peer() : A = newInstance那样直接在特征中使用它,但它在外面可以正常工作。
    • 我不确定我是否理解你的问题,但我更新了我的答案,提供了更多信息。
    • 我正在为 Scala 中的现有 API (Vaadin) 进行代理。我不想编写大量代码,因此,我可能希望为 PeerProxy 中的默认 Peer 构造函数提供一个干净的解决方案。
    • 如果您想查看代码的其他部分,可以在这里查看:github.com/un-jon/scala-vaadin/tree/master/core/src/main/scala/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多