Scala可变集:奇怪的行为

eje*_*211 3 scala set

我无法解释Scala集的这种行为.

让我们从几个定义开始.

import scala.collection.mutable.Set
case class Item(name: String, content: Set[Int])
val items: Set[Item] = Set.empty
Run Code Online (Sandbox Code Playgroud)

我会在我的套装中添加一个项目.

items += Item("name", Set(1, 2, 3))
Run Code Online (Sandbox Code Playgroud)

我会清空我的内心.

items.filter(_.name == "name") foreach (_.content -= 1)
items
// res7: scala.collection.mutable.Set[Item] = Set(Item(name,Set(2, 3)))
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.

items.filter(_.name == "name") foreach (_.content -= 2)
items.filter(_.name == "name") foreach (_.content -= 3)
items
// res12: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

完善!现在,我真正想做的是删除内部空集的条目.

items.retain(_.content.nonEmpty)
items
// res12: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

没工作.也许我做了相反的测试.

items.retain(_.content.isEmpty)
items
// res14: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

也没用.也许过滤器不起作用.

items.filter(_.content.nonEmpty)
// res15: scala.collection.mutable.Set[Item] = Set()
Run Code Online (Sandbox Code Playgroud)

过滤器工作正常.也许我无法改变它,因为它是一个val.

items += Item("name", Set.empty)
items
// res17: scala.collection.mutable.Set[Item] = Set(Item(name,Set()), Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

我可以改变它.并添加...更多相同?也许他们都不一样.

items += Item("name", Set.empty)
items
// res19: scala.collection.mutable.Set[Item] = Set(Item(name,Set()), Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

他们并非完全不同.那我可以删除它们中的任何一个吗?

items -= Item("name", Set.empty)
items
// res21: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

我可以删除一个.我可以删除另一个,我一直试图从一开始删除的那个吗?

items -= Item("name", Set.empty)
items
// res23: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))
Run Code Online (Sandbox Code Playgroud)

不.发生了什么?我很困惑.

编辑,解决方案:

使用此Stackoverflow帖子,Scala:忽略case类字段为equals/hascode?,我通过改变声明case类的方式解决了这个问题:

case class Item(name: String)(val content: Set[Int])
Run Code Online (Sandbox Code Playgroud)

这样,内部集合被忽略为哈希码并等于评估,但仍可作为字段访问.

Ale*_*nov 6

Item更改时的更改哈希码content.由于创建的集合Set(...)是散列集,因此如果其元素的散列发生更改,则无法正常工作.请注意,它是否Set[Item]可变是无关紧要的; 只有这content是可变的.

如果将可变对象放入哈希集或将它们用作哈希映射的键,则必须确保1)它们在那里不变异或2)它们的hashCode方法是稳定的.

  • "我确信每次都会重新计算平等和哈希值." 对,他们是.这正是问题所在:元素仍然存储在其旧的哈希值下,但是被当前哈希值查找. (2认同)