List中的canEqual对Set参数返回true

时间:2016-11-23 07:27:56

标签: scala

问题1 - 当我将List与Set(不同元素)进行比较时,为什么此代码返回true,但当我将List与List或Set进行比较时返回false?

scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)

scala> val l2=List(1,2,3)
l2: List[Int] = List(1, 2, 3)

scala> val l3=List(1,3,3)
l3: List[Int] = List(1, 3, 3)

scala> l.canEqual(l2)
res2: Boolean = true

/*I guess this returns true becuase canEqual check for type of the passed instance. Something like def canEqual(other: Any): Boolean = other.isInstanceOf[List] */

scala> l.canEqual(l3)
res3: Boolean = true

//but if canEqual checks for type of passed instance then why this returns true when I call canEqual on List but pass a Set

scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> l.canEqual(s)
res4: Boolean = true

scala> val s2=Set(2,3,4)
s2: scala.collection.immutable.Set[Int] = Set(2, 3, 4)

scala> l.canEqual(s)
res5: Boolean = true

scala> l.canEqual(s2)
res6: Boolean = true

列表中的canEqual可能不会检查实例List类型但是某些超类实例或者可能不会覆盖equals。是这种情况吗?

问题2 - 我读到canEquals与equals和hashcode一起使用来定义一个实例是否等于某个其他实例。 canEquals通常由equals调用。当用户直接从代码调用canEqual时,是否有用例(就像我上面尝试的那样)?

1 个答案:

答案 0 :(得分:5)

让我们从更简单的例子开始:

scala> "aaaa".canEqual(5)
res0: Boolean = true

所以默认情况下一切都是平等的 - 但它并不意味着它会是平等的。 canEqual的实际用例是禁用等效性(请参阅this article):

  

非最终类的canEqual方法。这允许子类   如果他们想要不允许等于父级,则覆盖canEqual   班级或兄弟班。

因此canEqual的全部原因是继承(在兄弟姐妹/父母中严格禁用相等)。建议不要在equals之外调用它,因为它违反了上面文章中所述的Liskov替换原则。

恕我直言,我根本不建议使用它,反直觉和dangerous。如果你需要禁用实体之间的相等性,那么最好选择组合到继承,因为继承在逻辑上需要继承相等,但组合更灵活。