Как использовать отражение на параметризованном признаке в Scala? - PullRequest
4 голосов
/ 01 августа 2011

Доступ к Манифесту кажется сложным из черты в Scala.

Как этот код может компилироваться в 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] }
}

Поскольку черты не могут предоставить манифест для параметризованной черты, класс, реализующий черту, должен, но я не получаю его.

1 Ответ

4 голосов
/ 01 августа 2011

О ковариации :

Поскольку 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]) { ....

Черты не могут иметь границы просмотра, потому что они не могут принимать никаких (значений) параметров.Но на самом деле это не проблема, потому что в вашем примере

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