我看到我正在处理的一些Scala 2.7.7代码有问题,如果等效代码是用Java编写的,则不会发生。松散地,这段代码创建了许多纸牌玩家并将其分配到表中。

class Player(val playerNumber : Int)

class Table (val tableNumber : Int) {
    var players : List[Player]  = List()

    def registerPlayer(player : Player) {
        println("Registering player " + player.playerNumber + " on table " + tableNumber)
        players = player :: players
    }
}

object PlayerRegistrar  {
    def assignPlayersToTables(playSamplesToExecute : Int, playersPerTable:Int) = {
        val numTables = playSamplesToExecute / playersPerTable
        val tables = (1 to numTables).map(new Table(_))
        assert(tables.size == numTables)

        (0 until playSamplesToExecute).foreach {playSample =>
            val tableNumber : Int = playSample % numTables
            tables(tableNumber).registerPlayer(new Player(playSample))
        }
        tables
    }
}


PlayerRegistrar在表之间分配许多玩家。首先,计算出需要多少张桌子来分摊玩家并创建一张列表。

然后,在代码的第二部分中,计算出应该将玩家分配到哪个表,从列表中拉出该表,并在该表上注册一个新玩家。

桌上的玩家列表是一个变量,每次调用registerPlayer()时都会被覆盖。我已经通过简单的TestNG测试检查了它是否可以正常工作:

@Test def testRegisterPlayer_multiplePlayers() {
    val table = new Table(1)
    (1 to 10).foreach { playerNumber =>
        val player = new Player(playerNumber)
        table.registerPlayer(player)
        assert(table.players.contains(player))
        assert(table.players.length == playerNumber)
    }
}


然后,我测试表分配:

  @Test def testAssignPlayerToTables_1table() = {
    val tables = PlayerRegistrar.assignPlayersToTables(10, 10)
    assertEquals(tables.length, 1)
    assertEquals(tables(0).players.length, 10)
}


测试失败,并显示“ expected: but was:”。我一直在挠头,但是无法弄清为什么registerPlayer()不会使列表中的表发生变化。任何帮助,将不胜感激。

最佳答案

原因是在assignPlayersToTables方法中,您正在创建一个新的Table对象。您可以通过在循环中添加一些调试来确认这一点:

val tableNumber : Int = playSample % numTables
println(tables(tableNumber))
tables(tableNumber).registerPlayer(new Player(playSample))


产生类似:

Main$$anon$1$Table@5c73a7ab
Registering player 0 on table 1
Main$$anon$1$Table@21f8c6df
Registering player 1 on table 1
Main$$anon$1$Table@53c86be5
Registering player 2 on table 1


请注意,表的内存地址对于每个调用而言是不同的。

出现这种情况的原因是,在Scala中Range是非严格的(无论如何,直到Scala 2.8)。这意味着直到需要时才评估对范围的调用。因此,您认为您正在返回Table对象的列表,但实际上您是在每次调用它时都返回一个经过评估(实例化一个新的Table对象)的范围。同样,您可以通过添加一些调试来确认这一点:

val tables = (1 to numTables).map(new Table(_))
println(tables)


这给你:

RangeM(Main$$anon$1$Table@5492bbba)


要执行所需的操作,请在末尾添加toList

val tables = (1 to numTables).map(new Table(_)).toList

10-07 18:56
查看更多