2

以下のコードで最も厄介なバグに遭遇しました。不変のマップとして渡しても、[マップ]ボタンは変化します。キーは同じままで、マップは2つの不変のIntを指していますが、下では、実行中にマップの値が明らかに異なることがわかります。私は絶対に困惑していて、何が起こっているのかわかりません。

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)
  })
}

これが出力です。クリア、マイナス、および5の状態変化を確認できます。

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

次に、自分が思っているのとまったく同じ地図を実際に印刷していることを確認してください。そのためには、参照 ID ハッシュ コードを使用するのが良い方法です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 に答える