Scala可以比较不兼容对象的原因和/或好处是什么?

时间:2011-09-07 09:20:12

标签: scala comparison

这让我感到困惑 - 我已经阅读了Scala存在的原因,并且常识引起了我的兴趣,例如选择静态类型(因为错误较少)。然而,你可以比较(开箱即用,默认情况下)完全不同的,不相关的对象,它编译并运行良好。对我来说,它只是需要更多的代码错误。

有人可以解释一下这个功能的原因是什么?还是好处?

我知道Scala在比较方面是如何工作的。我问为什么它的工作原理。

我希望,如果我想这样做,我会写隐式转换或显式比较。这种方法对我来说非常有意义,当前的Scala方式 - 不,因此我的问题。

还有一件事 - 我不知道如何使用Scala-way比较来获得一些奇特的效果,我正在寻找更严格的错误检查。 IOW:我不想按颜色比较Orange和Apple,我想默认禁止这样的比较,除非用户明确表示可以比较这些类型。

实施例

class Test
{
  val s : String = "ala"
}

class Foo
{
  val x : Int = 5
}

object Testbed 
{
  def main(args : Array[String])
  {
    val t = new Test
    val f = new Foo
    if (t==f)
      println("match")
    else
      println("no")
  }
}

4 个答案:

答案 0 :(得分:10)

嗯,简单的答案是==旨在与java.lang.Object.equals()兼容。由于任何类都可以覆盖equals(),因此Scala编译器无法确定两个对象之间的相等性检查结果,除非它在编译时知道对象的运行时类(即静态类型必须是最终类或编译等式检查时,new调用必须对编译器可见。并且在此类或任何超类中不会覆盖equals()方法。

因此,在您的示例中,编译器确实可以推断出tf的运行时类,并为相等性检查发出警告(但不是错误),但在实践中可以推断出运行时类是非常罕见的。请注意,scalac已经为基本类型和对象类型之间的某些相等比较发出警告。

P.S。如果您想要更安全的相等检查,请使用Scalaz中的Equal特征。

答案 1 :(得分:4)

scala中的等式是值相等(不是引用),等于通过覆盖equals可以定义的内容。基本上,==不是scala中的运算符,但是对于要测试相等性的对象的行为(实际上是IS)。 因此t == f实际上是t.==(f) ==,其中Any定义在class Test { val s : String = "ala" } class Foo { val x : Int = 5 override def equals(that: Any) : Boolean = { that.isInstanceOf[Test] && this.x == 5 && that.asInstanceOf[Test].s=="ala"; } } ,因此您可以在scala中的每个类上获取它。

例如(在你的例子中)你可以让你的Test ==变成Foo,就像这样:

scala> val t = new Test
t: Test = Test@86a58a

scala> val f = new Foo
f: Foo = Foo@104f889

scala> f==t
res3: Boolean = true

现在你得到:

scala> t==f
res4: Boolean = false

但是(因为我们没有在测试中覆盖等号)

{{1}}

虽然在这个特定情况下这并没有多大意义,但重点是scala让你决定什么使得Test等于Foo。如果他们拥有相同的社会安全号码,您是否希望某个人= =另一个人(或员工)?你可以实现这个逻辑。

然而,强大的力量带来了巨大的责任,事实上the concept of equality is surprisingly tricky

答案 2 :(得分:1)

在最近的主干版本中,您的示例会发出警告。我认为我发现误报的可能性与无意识的比较之间存在良好的平衡。在存在普遍平等和子类型的情况下,它比看起来更难。

% scalac3 ./a.scala 
./a.scala:20: warning: Test and Foo are unrelated: they will most likely never compare equal
    if (t==f)
         ^
one warning found

答案 3 :(得分:0)

  

我正在寻找更严格的错误检查。

最近(2016年5月)的帖子" Multiversal Equality for Scala",由Scala自己Martin Odersky的创建者撰写,正试图解决这个问题。

  

Scala中的当前状态是编译器将为一些始终为false的比较发出警告。但覆盖范围很弱。例如,这将发出警告:

scala> 1 == "abc"
<console>:12: warning: comparing values of types Int and String using `==' will always yield false
  

但这不会:

scala> "abc" == 1
res2: Boolean = false
  

我相信要做得更好,我们需要争取开发商的合作   最终,开发人员提供了平等方法的实现,因此最适合用于表征哪些等式有意义。

     

表征此类关系的最有名方法是使用类型类   trait Eq[T, U]的隐含值可以捕获属性T的值可以与U类型的值进行比较的属性。
  以下是Eq

的定义
package scala
trait Eq[-T, -U]
  

给定一组Eq个实例,我们的想法是Scala编译器会在每次遇到类型T和{{}值之间的可能有问题的比较时进行检查1}}有一个隐含的U实例   如果在不兼容的类型之间进行比较则可能存在问题   只要Eq[T, U]T <: U平等可能有意义,因为双方可能具有相同的价值。