2016-03-08 45 views
0

我试图创建一个Map对象是这样的:如何将默认地图值设置为scala中的新对象?

case class Worker(var name:String, var tasks:List[Int]=List()) 

val map = Map[Int, Worker]().withDefaultValue(Worker("")) 

所以,每当一个新的请求ID(在地图上的键)进来我可以创建该ID的新的工作对象。我不知道预先会有多少个请求ID将会进入或ID的范围。但是这段代码给出了一个非常奇怪的结果。

scala> map.size 
res34: Int = 0 

scala> map(1).name = "first worker" 
map(1).name: String = first worker 

scala> map.size 
res35: Int = 0 

scala> map(3).name = "request #3" 
map(3).name: String = request #3 

scala> map.size 
res36: Int = 0 

scala> map(1).name 
res37: String = request #3 

这不是我预期的结果。地图大小始终为0.没有创建新的Worker对象。我尝试了可变和不可变的Maps,案例类和普通类与新的工人,并尝试{ override def default(key:Int)=Worker("") }。没有按预期工作。有人可以帮助我理解withDefaultValue的行为或覆盖def default吗?或斯卡拉的方式来做到这一点?我知道我可以实现这种java方式if map.containsKey(xx) map.get(xx).name = "abc" else map.put(xx, new Worker)。但它很乏味。

回答

1

访问Map的默认值不会将该值作为新值添加到Map本身。你只是每次改变相同的默认值(相同的参考)。一个标准的Map实现会突变它自己是非常意外的。

要实现您想要的功能,您可能实际上想要覆盖apply方法,以便在找不到一个新元素时将其添加到Map

import scala.collection.mutable.HashMap 

case class Worker(var name: String, var tasks: List[Int] = Nil) 

class RequestMap extends HashMap[Int, Worker] { self => 

    override def apply(a: Int): Worker = { 
     super.get(a) match {   // Find the element through the parent implementation 
      case Some(value) => value // If it exists, return it 
      case None => {    
       val w = Worker("") // Otherwise make a new one 
       self += a -> w  // Add it to the Map with the desired key 
       w      // And return it 
      } 
     } 
    } 

} 

这是做你想做的,但它只是一个你可以采取的方向的例子。它不是线程安全的,并且需要某种锁定机制来实现它。

scala> val map = new RequestMap 
map: RequestMap = Map() 

scala> map(1) 
res3: Worker = Worker(,List()) 

scala> map(2) 
res4: Worker = Worker(,List()) 

scala> map.size 
res5: Int = 2 
+0

感谢您的解释。 – yang

相关问题