提问人:Polymerase 提问时间:7/22/2018 最后编辑:Andrey TyukinPolymerase 更新时间:7/22/2018 访问量:688
空列表相等性如何工作?
How does empty List equality work?
问:
运营商真的按内容比较列表吗?特别是关于空列表?==
以下比较按预期工作
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?
编辑:在最初的问题中,我做了一个误导性的测试用例,安德烈已经澄清了。谢谢。转载于此处
val emptyStrSplit = "".split("").toList // List("") and not List() as displayed in Console
List.empty[String] == emptyStrSplit // false: b/c List() != List("")
答:
List.empty[String]
是单例对象,它扩展(协变,子类型)。Nil
List[Nothing]
List[String]
List.empty[Int]
是单例对象,它扩展(协变,子类型)。Nil
List[Nothing]
List[Int]
- 每个单例对象都与自身相等。
- 因此,给出了真实。
Nil == Nil
因此,从本质上讲,您有一个同时具有类型和类型的对象。如果你有子类型,这就是你得到的。我在这里看不出有什么奇怪或矛盾的地方。Nil
List[String]
List[Int]
如果要确保类型相同,可以使用默认值为 type 的证据,然后检查编译器是否提供了非证据:implicit
A =:= B
null
null
def eqSameType[A, B](a: A, b: B)(implicit ev: A =:= B = null) =
if (ev == null) false else a == b
例:
scala> eqSameType(List.empty[Int], List.empty[String])
res4: Boolean = false
评论
List.empty[String] == List.empty[Int]
false
x == y
x
y
eqSameType(List.empty[List[String]], List.empty[List[Int]]) // false
A =:= B = null
=:=
=:=[A, B]
= null
ev
A =:= B
=:=
除了 Andrey 的回答之外,即使 (或 ) 确实返回了 的新实例 ,您仍然应该期望由于类型擦除而使各种类型的空列表相等。例如,以 为例,其方法每次都会返回一个 new: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
不过,我不确定这什么时候有用。
评论
TypeTag
ClassTag
equalAndSameType(List.empty[List[String]], List.empty[List[Int]])
编辑:这种实现使用还不够好。布莱恩的答案更好。ClassTag
TypeTag
尽管从Scala的角度来看,Andrey的回答非常有意义。我觉得必须是假的而不是真的更具有商业意义。下面是一个自定义比较器,使用上下文绑定来支持以下内容。不确定这是否是最优雅的方式。List.empty[String] == List.empty[Int]
import scala.reflect.{ClassTag, classTag}
def customCompareLists[T1: ClassTag, T2: ClassTag](l1: List[T1], l2: List[T2]): Boolean = {
classTag[T1] == classTag[T2] && l1 == l2
}
customCompareLists(List(), List()) // true
customCompareLists(List.empty[Double], List.empty[Double]) // true
customCompareLists(List.empty[String], List.empty[Int]) // false
customCompareLists(List(1,2), List("A")) // false
customCompareLists(List(1,2), List(1,2)) // true
// FAILED on this case
customCompareLists(List.empty[List[String]], List.empty[List[Int]]) // true: INCORRECT
评论
即使忽略类型擦除问题和“它们实际上是同一个对象”问题,on 的文档也指出:equals
Seq
def equals(that: Any): Boolean
任意序列的 equals 方法。
返回:如果该序列具有与此序列具有相同顺序的相同元素,则返回 true,否则返回 false
这使得所有空序列相等:它们以相同的顺序具有相同的元素,即 none。empty 等于空 、 、 等。List
Vector
Queue
Stream
评论
"".split("").toList
莫。它。在你删除空洞的错误假设后,这个问题是否仍然会问任何重要问题?List()
List("")
"".split("")
toString
笨拙且模棱两可 - in 中的空字符串在打印输出中是不可见的,因此它看起来像 .List("")
List()
List()
"".split("").toList
List.empty[T1] == List.empty[T2]