Problemi con gli oggetti aggiuntivi a un ListBuffer in Scala
-
28-10-2019 - |
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?
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. toList
ing 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.)