我正在尝试创建一个对象来存储对象创建的实例,并避免重新加载。我试图在对象上创建一个可变映射来存储它,但是我收到了编译错误。
这是我的代码:
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吗?或者以不同的方式解决这个问题?
答案 0 :(得分:1)
您的问题在于,您正在返回loaded(className)
类型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])
}
}