【问题标题】:Problems with appending objects to a ListBuffer in Scala将对象附加到 Scala 中的 ListBuffer 的问题
【发布时间】:2012-01-13 16:52:05
【问题描述】:

我在将对象附加到 scala.collection.mutable.ListBuffer 时遇到问题。我熟悉相应的 API,并且知道通常您使用 += 或 ++= 方法来添加对象或对象序列。

我正在实现一个支持网络的纸牌游戏,并且遇到一个简单的问题,就是将一些选择的牌添加到手牌列表中。在下面的代码中,我将获取对手牌列表(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)

正如人们所期望的那样,手牌的大小会随着所选卡片的大小而增长。但是输出是(格式化的):

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
}

在 Card 类中创建了一个 ClientCard:

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 后立即复制它。这解决了问题。有人对此行为有解释吗?

【问题讨论】:

  • ListBuffer 如果将其转换为列表,则会在幕后做一些花哨的事情。代码中有toLists 之类的吗?我无法复制您观察到的行为。
  • 不明确。但是在创建 handCards ListBuffer 之后,它会通过网络发送,因此会再次被序列化和反序列化。
  • 确实好像是ListBuffer的序列化和反序列化造成的。我为 ClientPlayer 创建了一个深拷贝方法,并在收到每个 ClientPlayer 对象后立即为其创建了一个副本。这解决了问题。
  • 有人对这种行为有解释吗?
  • 我可以将其重现为错误。我要开一张票。

标签: scala collections append listbuffer


【解决方案1】:

反序列化会产生一个非常脆弱的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 在反序列化时处于合理状态,而是重建它。 (您可能希望序列化和反序列化 List。)

【讨论】:

  • 是的,这似乎是问题所在。附加不会对我抛出异常,而是什么都不做,只是支持你的假设,即 ListBuffer 在反序列化后非常脆弱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多