5

Scala 2.9 では、ポリモーフィックなインスタンス化を次のように実装できます。

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

しかし、2.10 の時点でManifestは に置き換えられておりTypeTag、 で同様のことを達成する方法が明確ではありませんTypeTag。TypeTag バージョンが利用可能なすべての型情報を保持することを希望します。

上記は、コンストラクター引数を必要としない特性/クラスでのみ機能することを知っています。また、常に機能するとは限りませんが、必要なものには十分に機能します。私が新しいリフレクション API を改善できれば、それは素晴らしいことです。

4

2 に答える 2

9

TypeTagManifest実験的で不安定な Scala リフレクションの一部であるため、まだ の代替にはなりません。現時点では、本番環境では絶対に使用しないでください。

あなたが示したユースケースでは、ランタイムクラスのみが必要です(ジェネリックなどの完全な型情報ではありません)、Scala 2.10 が導入されましClassTagた。これは次のように使用できます。

def newInstance[T: ClassTag] =
  implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T]

また:

def newInstance[T](implicit ct: ClassTag[T]) =
  ct.runtimeClass.newInstance.asInstanceOf[T]

とにかく、Manifestまだ廃止されていないので、まだ使用できると思います。

編集:

TypeTag同じことを達成するために使用:

import scala.reflect.runtime.universe._

def newInstance[T: TypeTag] = {
  val clazz = typeTag[T].mirror.runtimeClass(typeOf[T])
  clazz.newInstance.asInstanceOf[T]
}

上記のソリューションでは、まだ Java リフレクションを使用しています。純粋主義で Scala リフレクションのみを使用したい場合、これが解決策です。

def newInstance[T: TypeTag]: T = {
  val tpe = typeOf[T]

  def fail = throw new IllegalArgumentException(s"Cannot instantiate $tpe")

  val noArgConstructor = tpe.member(nme.CONSTRUCTOR) match {
    case symbol: TermSymbol =>
      symbol.alternatives.collectFirst {
        case constr: MethodSymbol if constr.paramss == Nil || constr.paramss == List(Nil) => constr
      } getOrElse fail

    case NoSymbol => fail
  }
  val classMirror = typeTag[T].mirror.reflectClass(tpe.typeSymbol.asClass)
  classMirror.reflectConstructor(noArgConstructor).apply().asInstanceOf[T]
}
于 2013-08-28T22:44:20.083 に答える