简体   繁体   English

Scala可变集:奇怪的行为

[英]Scala mutable set: strange behavior

I can't explain this behavior of Scala sets. 我无法解释Scala集的这种行为。

Let's start with a few definitions. 让我们从几个定义开始。

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

I'll add an item to my set. 我会在我的套装中添加一个项目。

items += Item("name", Set(1, 2, 3))

I'll empty my inner set. 我会清空我的内心。

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

So far so good. 到现在为止还挺好。

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

Perfect! 完善! Now, what I REALLY want to do is remove the entries with an empty inner set. 现在,我真正想做的是删除内部空集的条目。

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

Didn't work. 没工作。 Maybe I did the opposite test. 也许我做了相反的测试。

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

Didn't work either. 也没用。 Maybe the filter doesn't work. 也许过滤器不起作用。

items.filter(_.content.nonEmpty)
// res15: scala.collection.mutable.Set[Item] = Set()

The filter works fine. 过滤器工作正常。 Maybe I can't change it because it's a val. 也许我无法改变它,因为它是一个val。

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

I CAN change it. 我可以改变它。 And add... more of the same? 并添加...更多相同? Maybe they're all different. 也许他们都不一样。

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

They're not all different. 他们并非完全不同。 So can I remove any of them? 那我可以删除它们中的任何一个吗?

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

I can remove ONE. 我可以删除一个。 Can I remove the other, the one I've been trying to remove from the start? 我可以删除另一个,我一直试图从一开始删除的那个吗?

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

Nope. 不。 What's happening? 发生了什么? I'm very confused. 我很困惑。

EDIT, SOLUTION: 编辑,解决方案:

Using this Stackoverflow post, Scala: Ignore case class field for equals/hascode? 使用此Stackoverflow帖子, Scala:忽略case类字段为equals / hascode? , I solved this by changing the way I declare the case class: ,我通过改变声明case类的方式解决了这个问题:

case class Item(name: String)(val content: Set[Int])

This way, the inner set is disregarded for hashcode and equals evaluations, but still accessible as a field. 这样,内部集合被忽略为哈希码并等于评估,但仍可作为字段访问。

Hashcode of Item changes when you change content . 更改content时, Item哈希码会更改。 Since a set created by Set(...) is a hash set, it can't work correctly if hashes of its elements change. 由于Set(...)创建的Set(...)是散列集,因此如果其元素的散列发生更改,则无法正常工作。 Note that it doesn't matter whether the Set[Item] is mutable or not; 请注意, Set[Item]是否可变是无关紧要的; only that content is mutable. 只有那些content是可变的。

If you put mutable objects into a hash set or use them as keys of a hash map, you must make sure that either 1) they aren't mutated while there or 2) their hashCode method is stable. 如果将可变对象放入哈希集或将它们用作哈希映射的键,则必须确保1)它们在那里或2)它们的hashCode方法稳定时不会发生变异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM