2012-01-13 3 views
4

У меня возникают проблемы с добавлением объектов в scala.collection.mutable.ListBuffer. Я знаком с соответствующим API и знаю, что обычно вы используете метод + = или ++ = для добавления объекта или последовательности объектов.Проблемы с добавлением объектов в ListBuffer в Scala

Я реализую карточную игру с поддержкой сети и имею простую задачу, добавив некоторые выбранных карт в Список ручных карт. В следующем коде я собираюсь получить ссылку на Список ручных карт (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(
    [email protected], 
    [email protected], 
    [email protected], 
    [email protected], 
    [email protected] 
) ++= List(
    [email protected], 
    [email protected] 
) 

number of hand cards: 5 

Таким образом, элементы не были добавлены.

Клиентская карта всегда является представителем «настоящей карты» и состоит только из информации, необходимой для рисования карты.

trait ClientCard extends AnyRef with ClientObject with CardLike 

trait ClientObject extends Serializable { 
    def uid: Int 
} 

trait CardLike { 
    val imagePath: String 
} 

ClientCard создается в классе карты:

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

И есть ClientPlayer (представитель "реального игрока"), где 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) 
} 

Кто-нибудь знает, что здесь происходит не так? Или быть более общим: какие существуют обстоятельства, чтобы предотвратить успешное добавление объектов в ListBuffer?

Редактировать: Есть что-то, что я забыл упомянуть и что, казалось, вызывало это странное поведение. После создания handCards ListBuffer он отправляется по сети и поэтому сериализуется и десериализуется снова.

После комментария Рекса Керра я попытался создать метод глубокой копии для ClientPlayer и скопировать каждый ClientPlayer сразу после его получения. Это решило проблему. У кого-нибудь есть объяснение этого поведения?

+0

'ListBuffer' делает некоторые причудливые вещи за кулисами, если он преобразуется в список. У вас есть какие-либо 'toList' или тому подобное в коде? Я не могу воспроизвести поведение, которое вы наблюдаете. –

+0

Неглубоко. Но после создания handCards ListBuffer он отправляется по сети и поэтому сериализуется и десериализуется снова. – Zwackelmann

+0

Это действительно было вызвано сериализацией и десериализацией ListBuffer. Я создал метод глубокой копии для ClientPlayer и создал копию для каждого объекта ClientPlayer сразу после его получения. Это решило проблему. – Zwackelmann

ответ

5

Deserialization производит необычайно хрупкую ListBuffer. Вероятно, это ошибка, но в качестве обходного пути вам нужно просто добавить его в какую-либо другую коллекцию (например, toList или добавить ее к пустой 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 находясь в разумное состояние при десериализации, а вместо этого перестроить его. (Возможно, вы захотите сериализовать и десериализовать List.)

+0

Да, это, кажется, проблема. Добавление не создает для меня исключение, но вместо этого просто ничего не делает, но я просто подтверждаю ваше предположение, что ListBuffer действительно чрезвычайно хрупок после десериализации. – Zwackelmann

Смежные вопросы