Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List Scala对象不更改其内部状态_List_Scala_State_Mutation - Fatal编程技术网

List Scala对象不更改其内部状态

List Scala对象不更改其内部状态,list,scala,state,mutation,List,Scala,State,Mutation,我发现我正在编写的一些Scala 2.7.7代码存在问题,如果它是用Java编写的,那么这种情况就不会发生。松散地说,代码会创建一组纸牌玩家并将其分配到表中 class Player(val playerNumber : Int) class Table (val tableNumber : Int) { var players : List[Player] = List() def registerPlayer(player : Player) { pri

我发现我正在编写的一些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)
}
测试因“预期:但为:”而失败。我一直在挠头,但不明白为什么registerPlayer()没有改变列表中的表。任何帮助都将不胜感激

val tables = (1 to numTables).map(new Table(_))
这一行似乎引起了所有的麻烦-映射
1到n
给了你一个好的结果,老实说,我不知道它们到底是如何工作的,但是一点不聪明的初始化技术就可以完成这项工作

var tables: Array[Table] = new Array(numTables)
for (i <- 0 to numTables) tables(i) = new Table(i)
var tables:Array[Table]=新数组(numTables)

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

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中是不严格的(至少在Scala 2.8之前)。这意味着对范围的调用在需要时才进行计算。因此,您认为您正在返回
对象的列表,但实际上您正在返回一个经过计算的范围(在每次调用时实例化一个新的
对象)。同样,您可以通过添加一些调试来确认这一点:

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

我无法尝试代码,但可以尝试在每个数字范围后添加
.toList
。您看到的结果可能是由于对范围的延迟计算。为什么您认为“每次调用registerPlayer()时,表上的玩家列表…都会被覆盖?”它会在表的任何给定实例中不受限制地增长。