Domanda

Ho problemi ad aggiungere oggetti a Scala.Collection.mutable.listBuffer. Conosco la rispettiva API e so che normalmente usi il metodo += o ++ = per aggiungere un oggetto o una sequenza di oggetti.

Sto implementando un gioco di carte con supporto di rete e ho il semplice problema di aggiungerne alcuni carte scelte a un elenco di Carte manuali. Nel seguente codice riceverò il riferimento all'elenco delle schede manuali (ListBuffer), stampare le dimensioni di ListBuffer, aggiungi il carte scelte A esso e stampare di nuovo le dimensioni.

// get the references and ensure that it are rally ListBuffers / Lists
val handCards: mutable.ListBuffer[ClientCard] = playerPanel.player.handCards
val chosenCards: List[ClientCard] = _chosenCards

// print the number of elements per list
println("number of hand cards: " + handCards.size)
println("number of chosen cards: " + chosenCards.size)

// append the chosen cards to the hand cards
println("append operation: " + handCards + " ++= " + chosenCards)
handCards ++= chosenCards

// print the number of hand cards again
println("number of hand cards: " + handCards.size)

Come il risultato ci si aspetterebbe, che le dimensioni delle carnane cresceranno delle dimensioni delle carte scelte. Ma l'output è (formata):

number of hand cards: 5
number of chosen cards: 2

append operation: ListBuffer(
    rftg.card.Card$$anon$1@1304043, 
    rftg.card.Card$$anon$1@cb07ef, 
    rftg.card.Card$$anon$1@176086d, 
    rftg.card.Card$$anon$1@234265, 
    rftg.card.Card$$anon$1@dc1f04
) ++= List(
    rftg.card.Card$$anon$1@1784427, 
    rftg.card.Card$$anon$1@c272bc
)

number of hand cards: 5

Quindi gli elementi non sono stati aggiunti.

Un ClientCard è sempre un rappresentante di una "carta reale" e consiste solo in informazioni necessarie per disegnare la carta.

trait ClientCard extends AnyRef with ClientObject with CardLike

trait ClientObject extends Serializable {
    def uid: Int
}

trait CardLike {
    val imagePath: String
}

Una ClientCard viene creata nella classe della scheda:

def clientCard = new ClientCard() {
    val uid = Card.this.hashCode()
    val imagePath = CardTemplate.cardFolder + Card.this.imageFilename
}

E c'è il cliente cliente (il rappresentante di un "vero lettore") in cui viene creato ListBuffer:

// definition of ClientPlayer trait
trait ClientPlayer extends ClientObject {
    val victoryPoints: Int
    val handCards: mutable.ListBuffer[ClientCard] 
    val playedCards: mutable.ListBuffer[ClientCard]
}

// piece of code to create a client player
def clientPlayer = new ClientPlayer() {
    val uid = Player.this.hashCode()
    val victoryPoints = Player.this.victoryPoints

    val handCards = new mutable.ListBuffer[ClientCard]
    handCards ++= (Player.this.handCards.map(_.clientCard)) 

    val playedCards = new mutable.ListBuffer[ClientCard]
    playedCards ++= Player.this.playedCards.map(_.clientCard)
}

Qualcuno sa cosa non va qui? O per essere più generici: quali circostanze ci sono per impedire l'apprendimento riuscita degli oggetti a un ListBuffer?

EDIT: c'è qualcosa che ho dimenticato di menzionare e ciò che sembrava causare questo strano comportamento. Dopo la creazione di The Hand Chards ListBuffer, viene inviato sulla rete e quindi viene nuovamente serializzato e deserializzato.

Dopo il commento di Rex Kerr ho provato a creare un metodo a copia profonda per un cliente e ho copiato ogni clientela subito dopo averlo ricevuto. Ciò ha risolto il problema. Qualcuno ha una spiegazione per questo comportamento?

È stato utile?

Soluzione

La deserializzazione produce una straordinariamente fragile ListBuffer. Questo è probabilmente un bug, ma come soluzione alternativa, il solo cosa che dovresti farci è immediatamente aggiungerlo a qualche altra collezione (ad es. toListing o aggiungendolo a un vuoto ListBuffer).

Ecco un codice che puoi usare per verificare che la serializzazione/deserializzazione sia problematica:

import collection.mutable.ListBuffer
import java.io._
val baos = new ByteArrayOutputStream
val oos = new ObjectOutputStream(baos)
oos.writeObject( ListBuffer(1,2,3) )
val bais = new ByteArrayInputStream( baos.toByteArray )
val ois = new ObjectInputStream(bais)
val lb = ois.readObject.asInstanceOf[ListBuffer[Int]]
val lb2 = ListBuffer[Int]() ++= lb
lb2 ++= List(1)  // All okay
lb ++= List(1)  // Throws an exception for me

Invierò un rapporto di bug, ma per il momento dovresti non fare affidamento sul ListBuffer essere in uno stato sensato quando deserializzato, e invece ricostruirlo. (Potresti voler serializzare e deserializzare a List invece.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top