4

オブジェクトを scala.collection.mutable.ListBuffer に追加する際に問題があります。私はそれぞれの API に精通しており、通常は += または ++= メソッドを使用してオブジェクトまたはオブジェクトのシーケンスを追加することを知っています。

ネットワークをサポートするカード ゲームを実装していますが、選択したカードを List of hand cardsに追加するという単純な問題があります。次のコードでは、ハンド カードのリスト (ListBuffer) への参照を取得し、ListBuffer のサイズを出力し、選択したカードをそれに追加して、サイズを再度出力します。

// 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)

結果として、handCards のサイズは、選択したカードのサイズだけ大きくなります。しかし、出力は(フォーマットされています):

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

したがって、要素は追加されていません。

ClientCard は常に「実際のカード」の代表であり、カードを引くために必要な情報のみで構成されます。

trait ClientCard extends AnyRef with ClientObject with CardLike

trait ClientObject extends Serializable {
    def uid: Int
}

trait CardLike {
    val imagePath: String
}

ClientCard は Card クラスで作成されます。

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

そして、ListBuffer が作成される ClientPlayer (「実際のプレーヤー」の代表) があります。

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

ここで何がうまくいかないのか誰か知っていますか?または、より一般的に言えば、ListBuffer へのオブジェクトの追加が成功しないのはどのような状況ですか?

編集:私が言及するのを忘れていたものと、この奇妙な動作の原因と思われるものがあります. handCards ListBuffer の作成後、ネットワーク経由で送信されるため、再度シリアライズおよびデシリアライズされます。

Rex Kerr のコメントの後、私は ClientPlayer のディープ コピー メソッドを作成しようとし、それを受け取った直後に各 ClientPlayer をコピーしました。これで問題は解決しました。誰かがこの動作について説明していますか?

4

1 に答える 1

5

逆シリアル化により、非常に壊れやすいListBuffer. これはおそらくバグですが、回避策として、すぐに他のコレクションに追加する必要があります (たとえば、toListing するか、空の に追加しますListBuffer)。

シリアライゼーション/デシリアライゼーションに問題があることを確認するために使用できるコードを次に示します。

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

バグレポートを提出しますが、当面は、デシリアライズ時に適切な状態にあることに依存せず、再構築してください。ListBuffer(代わりに a をシリアライズおよびデシリアライズすることをお勧めしListます。)

于 2012-01-13T19:01:42.310 に答える