2013-07-21 25 views
0

我想创建一个对象来存储对象创建的实例并避免重新加载。我试图在对象上创建一个可变映射来存储它,但是我得到一个编译错误。如何在scala中创建一个多态类型的对象属性

这是我的代码:

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'还是解决这个不同呢?

回答

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]) 
    } 
} 
+1

你可以用'情况下,一些:我认为比赛正常,由于classtag(巴T)=> bar'。你也可以(或许更好)使用'getOrElseUpdate' –

+0

@ 0__,是的,你是对的。每天我都会学习有关Scala标准库的新内容) –

相关问题