Pergunta

Estou vendo um problema com algum código Scala 2.7.7 em que estou trabalhando, que não deve acontecer se o equivalente foi escrito em Java. Pouco, o código vai cria um monte de jogadores de cartas e os atribui a tabelas.

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

O PlayerRegistrar atribui vários jogadores entre as tabelas. Primeiro, funciona quantas tabelas precisarão quebrar os jogadores e criar uma lista deles.

Então, na segunda parte do código, ele funciona a qual tabela um jogador deve ser atribuído, puxa essa tabela da lista e registra um novo jogador nessa tabela.

A lista de jogadores em uma tabela é um VAR e é substituída cada vez que o registroPlayer () é chamado. Eu verifiquei se isso funciona corretamente através de um teste de teste simples:

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

Eu então testo a atribuição da tabela:

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

O teste falha com "Esperado: <10> mas foi: <0>". Eu estive coçando a cabeça, mas não consigo descobrir por que o RegisterPlayer () não está mudando a tabela na lista. Qualquer ajuda seria apreciada.

Foi útil?

Solução

A razão é que no assignPlayersToTables Método, você está criando um novo Table objeto. Você pode confirmar isso adicionando alguma depuração ao loop:

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

Cedendo algo como:

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

Observe como o endereço de memória da tabela é diferente para cada chamada.

A razão para esse comportamento é que um Range Não é rigoroso em Scala (até Scala 2.8, de qualquer maneira). Isso significa que a chamada para o intervalo não é avaliada até que seja necessária. Então você acha que está recebendo uma lista de Table objetos, mas na verdade você está recebendo um intervalo que é avaliado (instanciando um novo Table objeto) cada vez que você chama. Novamente, você pode confirmar isso adicionando algumas depuração:

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

O que lhe dá:

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

Para fazer o que quiser, adicione um toList até o fim:

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

Outras dicas

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

Essa linha parece estar causando todo o problema - mapeando 1 to n dá a você um RandomAccessSeq.Projection, E, para ser sincero, não sei exatamente como eles funcionam, mas uma técnica de inicialização um pouco menos inteligente faz o trabalho.

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

Usando o primeiro método de inicialização, não consegui alterar os objetos (como você), mas usando uma matriz simples, tudo parece estar funcionando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top