List Scala对象不更改其内部状态
我发现我正在编写的一些Scala 2.7.7代码存在问题,如果它是用Java编写的,那么这种情况就不会发生。松散地说,代码会创建一组纸牌玩家并将其分配到表中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
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()时,表上的玩家列表…都会被覆盖?”它会在表的任何给定实例中不受限制地增长。