Scala中的平等关系

Scala中的平等关系,scala,scala-2.8,equals,equality,scala-collections,Scala,Scala 2.8,Equals,Equality,Scala Collections,我只是偶然发现了Tony Morris的一个观点和语言的一个基本问题:为收藏定义定制的平等关系。这是一件大事,我想知道是否有scala的解决方案 经典问题表现在思考,比如说,交易。假设我以150便士的价格进行了两次+100股沃达丰股票的交易。这两个行业是平等的,是吗?但他们不是同一行业。对于具有持久性或序列化的正常现实世界系统,我不能依靠标识来告诉我两个引用是否指向同一交易 因此,我希望能够创建一个集合,我可以将相等关系传递给: val as = CleverSet[Trade](IdEqual

我只是偶然发现了Tony Morris的一个观点和语言的一个基本问题:为收藏定义定制的平等关系。这是一件大事,我想知道是否有scala的解决方案

经典问题表现在思考,比如说,交易。假设我以150便士的价格进行了两次+100股沃达丰股票的交易。这两个行业是平等的,是吗?但他们不是同一行业。对于具有持久性或序列化的正常现实世界系统,我不能依靠标识来告诉我两个引用是否指向同一交易

因此,我希望能够创建一个集合,我可以将相等关系传递给:

val as = CleverSet[Trade](IdEquality)
val bs = CleverSet[Trade](EconomicsEquality)
我如何高效地实现我的集合(除非
EqualityRelation
也定义了
hash
机制)

因此,问题是:

  • 是否有提供此功能的库
  • 在Scala中有什么方法可以做到这一点吗

似乎有了隐式,添加到现有的scala
集合
类型将是一件非常容易的事情。

这可以通过Java的TreeSet和Comparator实现:

TreeSet<String> ignoreCase = new TreeSet<String>(new Comparator<String>(){
    @Override
    public int compare(String o1, String o2) {
        return o1.compareToIgnoreCase(o2);
    }});

TreeSet<String> withCase = new TreeSet<String>();

List<String> values = asList("A", "a");
ignoreCase.addAll(values);
withCase.addAll(values);
这样做的缺点是,要实现的比较器比需要的功能更强大,并且您仅限于支持比较器的集合。正如oxbow_lakes指出的那样,比较器实现打破了集合契约(对于
!a.equals(b)
,可能是
newset();Set.add(a)==true&&Set.add(b)==false

Scala通过从a=>Ordered[a]进行视图转换来支持这一点

scala> new scala.collection.immutable.TreeSet[String]()(x=> x.toLowerCase) + "a"
 + "A"
res0: scala.collection.immutable.TreeSet[String] = Set(A)

您正在描述哈希策略的概念。其中包括可以使用哈希策略构建的集合和映射。

我知道您在询问Scala,但它值得与.Net集合提供的内容进行比较。特别是,所有基于哈希的集合(例如
字典
哈希集
)都可以采用。这类似于Scala,但也提供了自定义哈希代码。您可以通过子类化
Equiv
创建类似的特征:

trait HashEquiv[T] extends Equiv[T] {
  def hashOf(t: T) : Int
}

要得到完全支持,基于哈希的集合需要在其构造中添加
HashEquiv
隐式参数,并使用隐式导入的
equiv
hashOf
方法,而不是
对象
实例方法(如
TreeSet
,等与
有序的特征相关,但与之相反)。还需要从
Any
隐式转换到
HashEquiv
,使用内在的
equals
hashCode
实现。

Scalaz中有Equal:。但我不太熟悉如何构建它。我认为这只是一个类型安全的equals,因此
“你好”===2
不编译calaz。Equal不仅是类型安全的,它还是一个灵活的。
Equal[List[Foo]]
可以通过
Equal[Foo]
进行参数化。这已经实现了你的目标。Martin Odersky拒绝将
Hash[T]
添加到标准库中,他说“我们想要维护通用散列,它是Java文化的太多部分。”并且您被迫沿着树结构的O(log(n))访问时间的路线前进。同样,从
TreeSet
的JavaDoc开始:请注意,由集合维护的顺序(无论是否提供显式比较器)如果要正确实现Set接口,必须与equals保持一致,因此,虽然这种方法有效,但似乎感觉不太正确这是一个有效的观点。破坏Set契约是一个坏主意。如果你将此树集交给他人,则必须对其进行包装。你建议的CleverSet将以同样的方式破坏它。它只能plement Iterable[T]不是Set[T]。这只是因为
Set
是用equal定义的。哦,我多么希望它是用(可插入的)equality定义的relation@oxbow_lakes-如果沿着这条路走下去(灵活性),java.lang.Object接口上只剩下getClass。
scala> new scala.collection.immutable.TreeSet[String]()(x=> x.toLowerCase) + "a"
 + "A"
res0: scala.collection.immutable.TreeSet[String] = Set(A)
trait HashEquiv[T] extends Equiv[T] {
  def hashOf(t: T) : Int
}