0

オブジェクトが作成したインスタンスを格納し、再読み込みを避けるオブジェクトを作成しようとしています。オブジェクトに変更可能なマップを作成して格納しようとしましたが、コンパイル エラーが発生します。

これは私のコードです:

class Bar

class FooBar extends Bar

object Foo {
    val loaded = scala.collection.mutable.Map[String, Bar]()

    def apply[T <: Bar](implicit m: Manifest[T]): T = {
        val className = m.toString()
        if (loaded.contains(className)) {
            return loaded(className)
        }
        val instance = m.runtimeClass.newInstance().asInstanceOf[T]
        loaded(className) = instance
        instance
    }
}

しかし、コンパイルしようとすると、次のエラーが発生します。

error: type mismatch;
 found   : Bar
 required: T
       return loaded(className)

マップを動的に作成して T? を渡す別の方法があります。または、これを別の方法で解決しますか?

4

1 に答える 1

1

あなたの問題は、関数型の署名で必要とされるのではなくloaded(className)、 type の which を返すことです。残念ながら、少なくとも標準のマップ コレクションでは、マップ キーと値のタイプ間の依存関係をエンコードすることはできません。明示的なキャストを実行する必要があります。これが実際の例です:BarT

import scala.reflect.ClassTag

class Bar

class FooBar extends Bar

object Test {
  val classMap = scala.collection.mutable.Map[Class[_], Bar]()

  def getInstance[T <: Bar : ClassTag]: T = {
    val ct = implicitly[ClassTag[T]]
    classMap get ct.runtimeClass match {
      case Some(bar) => bar.asInstanceOf[T]
      case None =>
        val instance = ct.runtimeClass.newInstance().asInstanceOf[T]
        classMap(ct.runtimeClass) = instance
        instance
    }
  }
}

object Main {
  def main(args: Array[String]) {
    println(Test.getInstance[FooBar])
    println(Test.getInstance[Bar])
    println(Test.getInstance[FooBar])
  }
}

ClassTagの代わりに使用していることに注意してください。ManifestなぜならManifest非推奨です。その現代的な同等物は ですTypeTagが、このタスクClassTagには十分すぎるほどです。

アップデート

@0__ によって提案されたコードの変形を次に示します。初め:

import scala.reflect.ClassTag

class Bar

class FooBar extends Bar

object Test {
  val classMap = scala.collection.mutable.Map[Class[_], Bar]()

  def getInstance[T <: Bar : ClassTag]: T = {
    val ct = implicitly[ClassTag[T]]
    classMap get ct.runtimeClass match {
      case Some(bar: T) => bar
      case None =>
        val instance = ct.runtimeClass.newInstance().asInstanceOf[T]
        classMap(ct.runtimeClass) = instance
        instance
    }
  }
}

object Main {
  def main(args: Array[String]) {
    println(Test.getInstance[FooBar])
    println(Test.getInstance[Bar])
    println(Test.getInstance[FooBar])
  }
}

そして第二に、最高のIMO:

import scala.reflect.ClassTag

class Bar

class FooBar extends Bar

object Test {
  val classMap = scala.collection.mutable.Map[Class[_], Bar]()

  def getInstance[T <: Bar : ClassTag]: T = {
    val ct = implicitly[ClassTag[T]]
    classMap.getOrElseUpdate(ct.runtimeClass, ct.runtimeClass.newInstance().asInstanceOf[Bar]).asInstanceOf[T]
  }
}

object Main {
  def main(args: Array[String]) {
    println(Test.getInstance[FooBar])
    println(Test.getInstance[Bar])
    println(Test.getInstance[FooBar])
  }
}
于 2013-07-21T19:54:46.913 に答える