2

我在下面的代码中遇到了一个最令人不安的错误。即使我将其作为不可变 Map 传递,按钮 Map 也会发生变化。键保持不变,map 指向两个不可变的 Ints,但在下面您可以看到 map 在运行期间明显具有不同的值。我完全被难住了,不知道发生了什么。

def makeTrace(trace : List[(String)], buttons : Map[String, (Int,Int)],
  outputScreen : ScreenRegion, hashMap : Map[Array[Byte], String])
  : (List[(String,String)], Map[Array[Byte], String]) = {

println(buttons.toString)
//clearing the device
val clear = buttons.getOrElse("clear", throw new Exception("Clear Not Found"))
//clear.circle(3000)
val thisButton = new ScreenLocation(clear._1, clear._2)
click(thisButton)

//updates the map and returns a list of (transition, state)
trace.foldLeft((Nil : List[(String,String)], hashMap))( (list, trace) => {
  println(buttons.toString)
  val transition : String = trace
  val location = buttons.getOrElse(transition, throw new Exception("whatever"))
  val button = new ScreenLocation(location._1, location._2)
  button.circle(500)
  button.label(transition, 500)
  click(button)

  //reading and hashing
  pause(500)
  val capturedImage : BufferedImage = outputScreen.capture()
  val outputStream : ByteArrayOutputStream = new ByteArrayOutputStream();
  ImageIO.write(capturedImage, "png", outputStream)
  val byte : Array[Byte] = outputStream.toByteArray();
  //end hash

  //if our state exists for the hash
  if (hashMap.contains(byte)){ list match {
    case (accumulator, map) => ((transition , hashMap.getOrElse(byte, throw new Exception("Our map broke if"))):: accumulator, map)
  }
  //if we need to update the map
  }else list match {
    case (accumulator, map) => {
      //adding a new state based on the maps size
      val newMap : Map[Array[Byte], String] = map + ((byte , "State" + map.size.toString))
        val imageFile : File = new File("State" + map.size.toString + ".png");
        ImageIO.write(capturedImage, "png", imageFile);
      ((transition, newMap.getOrElse(byte, throw new Exception("Our map broke else"))) :: accumulator, newMap)
    }        
  }  
})

}

在调用此函数之前,我将映射初始化为指向不可变对象的不可变映射。

    val buttons = makeImmutable(MutButtons)
    val traceAndMap = TraceFinder.makeTrace(("clear" ::"five"::"five"::"minus"::"five"::"equals":: Nil), buttons, outputScreen, Map.empty)

makeImmutable 在哪里

def makeImmutable(buttons : Map[String, (Int,Int)]) : Map[String, (Int,Int)] = {
  buttons.mapValues(button => button match {
    case (x, y) => 
      val newX = x
      val newY = y
      (newX,newY)
  })
}

这是输出,你可以看到清除、减号和五的状态变化

Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (842,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (842,377))
Map(equals -> (959,425), clear -> (959,345), minus -> (920,409), five -> (842,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (842,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (881,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (842,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,441), five -> (842,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (881,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (842,377))
Map(equals -> (959,425), clear -> (842,313), minus -> (920,409), five -> (842,377))
4

2 回答 2

2

首先,尝试散布println(map.getClass)在您的代码周围。确保它确实是您认为的地图。immutable它的包名中应该有,例如:

scala> println(Map(1->1, 2->2, 3->3, 4->4).getClass)
class scala.collection.immutable.Map$Map4

其次,确保您打印的地图与您认为的完全相同;使用参考身份哈希码是一个很好的方法:println(System.identityHashCode(map)).

很有可能这些事情之一不会给你预期的结果。然后你只需要找出问题在哪里泄漏。没有一个完整的可运行示例,如果没有过多的代码凝视,很难提供更好的建议。

于 2013-03-16T22:16:07.523 回答
0

我怀疑你在 makeImmutable 函数的范围内有一个 scala.collection.Map 的导入,它允许你将 MutButtons(可能是一个可变的 Map)传递给 makeImmutable 函数。Map 上的 mapValues 方法返回底层地图的视图,而不是不可变的副本。例如:

import scala.collection.Map
import scala.collection.mutable.{Map => MutableMap}

def doubleValues(m: Map[Int, Int]) = m mapValues { _ * 2 }

val m = MutableMap(1 -> 1, 2 -> 2)
val n = doubleValues(m)
println("m = " + m)
println("n = " + n)
m += (3 -> 3)
println("n = " + n)

运行这个程序会产生这个输出:

m = Map(2 -> 2, 1 -> 1)
n = Map(2 -> 4, 1 -> 2)
n = Map(2 -> 4, 1 -> 2, 3 -> 6)

要从 makeImmutable 返回真正不可变的映射,请在映射值后调用 .toMap。

于 2013-03-16T21:30:06.237 回答