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 Bar,而不是T函数类型签名所要求的。不幸的是,您不能编码映射键和值类型之间的这种依赖关系,至少不能使用标准映射集合。您必须执行显式强制转换。这是一个工作示例:

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 回答