空列表相等性如何工作?

时间:2018-07-21 17:58:10

标签: scala types equals equality subtyping

==运算符是否真的按内容比较列表?特别是关于空列表?

以下比较符合预期

List("A", "B", "C") == "ABC".split("").toList // true
List() == List() // true
List.empty[String] == List.empty[String] // true

但是,不同类型的空列表比较会产生令人困惑的结果:

List.empty[String] == List.empty[Int] // true: on different types?

编辑:在第一个问题中,我提出了一个误导性的测试案例,安德烈(Andrey)对此进行了澄清。谢谢。转载在这里

val emptyStrSplit = "".split("").toList // List("") and not List() as displayed in Console
List.empty[String] == emptyStrSplit // false: b/c List() != List("")

4 个答案:

答案 0 :(得分:5)

  • List.empty[String]是单例对象Nil,它扩展了List[Nothing](协变,List[String]的子类型)。
  • List.empty[Int]是单例对象Nil,它扩展了List[Nothing](协变,List[Int]的子类型)。
  • 每个单例对象都等于自己。
  • 因此,Nil == Nil为true。

因此,从本质上讲,您有一个对象Nil,它同时具有List[String]类型和List[Int]类型。这就是子类型化的结果。我在这里看不到任何奇怪或矛盾的地方。

如果要确保类型相同,可以使用implicit类型的A =:= B证据作为默认值null,然后检查是否非{{1 }}证据由编译器提供:

null

示例:

def eqSameType[A, B](a: A, b: B)(implicit ev: A =:= B = null) = 
  if (ev == null) false else a == b

答案 1 :(得分:4)

即使忽略类型擦除问题和“它们实际上是同一对象”问题,equalsSeq的文档也指出:

  

def equals(that: Any): Boolean

     

用于任意序列的equals方法。

     

返回:如果该序列具有与该序列相同的元素且顺序相同,则为true,否则为false

使所有空序列相等:它们具有相同元素的顺序相同,即没有。空List等于空VectorQueueStream等。

您可能还对提供类型安全的相等性的库感兴趣,例如ScalacticScalaz

答案 2 :(得分:1)

除了Andrey的答案外,即使List.empty[T](或List[T]())确实返回了List的新实例,由于类型不同,您仍然应该期望各种类型的空列表相等删除。例如,使用ListBuffer,其empty方法每次都会返回新的ListBuffer

import scala.collection.mutable.ListBuffer
ListBuffer.empty[Int] == ListBuffer.empty[String]

如果您想要一种方法来检测两个列表何时具有不同的编译时类型,则可以使用TypeTags

import scala.reflect.runtime.universe.{ TypeTag, typeTag }

def equalAndSameType[A: TypeTag, B: TypeTag](as: Seq[A], bs: Seq[B]) =
  typeTag[A] == typeTag[B] && as == bs

equalAndSameType(List.empty[Int], List.empty[String]) // returns false

不过,我不确定这何时会有用。

答案 3 :(得分:0)

编辑:使用$('.#open_lightbox').on('click', function(ev) { setTimeout(function() { $("#video1")[0].src += "&autoplay=1"; },150); //ev.preventDefault(); }); 的此实现还不够好。 Brian使用ClassTag的答案更好。

尽管从Scala的角度来看,Andrey的回答是完全合理的。我认为让TypeTag为假而不是真更具商业意义。以下是使用上下文的自定义比较器,该上下文必须支持以下内容。不确定这是否是最优雅的方式。

List.empty[String] == List.empty[Int]