在Scala中,我能否创建一个使用不同的equals / hashCode / compare实现的集合?

5
我正在寻找一种简单的方法来创建一个身份集。我只想能够跟踪我是否在遍历图形时“看到”了特定对象。
我不能使用常规Set,因为Set使用“==”(Scala中的equals方法)来比较元素。我想要的是一个使用“eq”进行比较的Set。
有没有办法在Scala中创建一个Set,该Set使用某些应用程序指定的方法来测试相等性,而不是在集合元素上调用equals?我寻找了一些可以覆盖的“wrapEquals”方法,但没有找到它。
我知道我可以使用Java的IdentityHashMap,但我正在寻找更通用的东西。
我另一个想法是只需将每个集合元素包装在另一个实现eq的对象中,但是生成大量新对象只是为了获得新的equals实现,这是浪费的。
谢谢!
3个回答

3

根据您的需求,您可以创建一个框,其中对包含的元素进行身份验证检查,例如:

class IdentBox[T <: AnyRef](val value: T) {

    override def equals(other: Any): Boolean = other match {
      case that: IdentBox[T] => that.value eq this.value
      case _ => false
    }

    override def hashCode(): Int = value.hashCode

  }

将集合内容改为包含那些盒子而不是直接包含元素:Set[IdentBox[T]]。

这种方式可能会有一些装箱/拆箱的开销,但在您的使用情况下可能是可以容忍的。


你提供的 hashCode 是可行的(实际上只要对于相同的实例返回相同的值,任何哈希函数都是可行的),但也许使用 System.identityHashCode(value) 会更好? - Suma
我对Willis Blackburn在这个问题的另一个答案中的评论感到不确定:不幸的是,System.identityHashCode返回默认的哈希码值,而不是地址,因此两个不同的对象可以具有相同的identityHashCode值。 - Miquel
identityHashCode是一个32位值(int),因此在64位JVM上不能保证其唯一性。尽管如此,它仍然比与case class值相等配合设计的hashValue更具唯一性,这正是您现在正在使用的内容。在您的情况下,任何东西都可以工作,因为您不会使用identityHashCode来执行比较,只需作为哈希值来伴随基于eq的比较即可。 - Suma

1

这个是一个类似的问题。在那种情况下,被接受的答案是使用TreeSet并提供自定义的Comparator


-1

既然您不需要对“seen”对象的引用,只需要一个“包含”的布尔值,我建议只使用mutable.Set[Int]并使用通过调用System.identityHashCode(obj)获取的值进行加载。

Scala自定义集合有足够的概念表面积来吓退大多数想要快速调整的人。


3
很遗憾,System.identityHashCode返回的是默认哈希码值,而不是地址,因此两个不同的对象可能具有相同的identityHashCode值。它可能在32位JVM中运行正常,但在64位JVM中会出现一些冲突。 - Willis Blackburn
1
只有当你希望你的软件每次都能正常工作时,这才是一个问题。 :-) - Mitch Blevins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接