Scala List.diff.intersect和.union未按预期工作

Scala List.diff.intersect和.union未按预期工作,scala,Scala,使用下面的代码可以得到以下结果: List(a, b) List() List(a, b, b, c) 我想要的当然是这样的结果: List(a) List(b) List(a, b, b, c) 我认为这是因为diff并集和intersect是关于“==”的。 问题是“==”-运算符是最终的,不能在类“Test”中重写 我怎样才能达到我期望的结果 下面是使用过的代码: package scalatest; public class JStringHolder { String s = n

使用下面的代码可以得到以下结果:

List(a, b)
List()
List(a, b, b, c)
我想要的当然是这样的结果:

List(a)
List(b)
List(a, b, b, c)
我认为这是因为diff并集和intersect是关于“==”的。 问题是“==”-运算符是最终的,不能在类“Test”中重写

我怎样才能达到我期望的结果

下面是使用过的代码:

package scalatest;

public class JStringHolder {
String s = null;

public JStringHolder(String newString){
    s = newString;
}

@Override
public String toString() {
    return s;
}

@Override
public boolean equals(Object obj) {
    System.out.println("SHEQ " + this.s + " AND " + ((JStringHolder)obj).s + " " + this.s.equals(((JStringHolder)obj).s));
    return this.s.equals(((JStringHolder)obj).s);
}
}
package scalatest;

public class JStringHolder {
String s = null;

public JStringHolder(String newString){
    s = newString;
}

@Override
public String toString() {
    return s;
}

@Override
public boolean equals(Object obj) {
    return this.s.equals(((JStringHolder)obj).s);
}
@Override
public int hashCode() {
    return s.hashCode();
}
}
以及要执行的scala代码:

package scalatest

object ListTest {

  trait AbstractTest 
  case class Test(stringHolder: scalatest.JStringHolder) extends AbstractTest {
    override def toString = stringHolder.toString()
    override def equals(ot: Any) : Boolean = {
      return stringHolder.equals(ot.asInstanceOf[Test].stringHolder)
    }

  }

  def main(args : Array[String]) : Unit = {
    val l1 = List(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
    val l2 = List(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
    println (l1.diff(l2))
    println (l1.intersect(l2))
    println (l1.union(l2))
  }
}
package scalatest

object ListTest {

  trait AbstractTest 
  case class Test(stringHolder: scalatest.JStringHolder) extends AbstractTest {
    override def toString = stringHolder.toString()
    override def equals(ot: Any) : Boolean = {
      return stringHolder.equals(ot.asInstanceOf[Test].stringHolder)
    }
    override def hashCode() : Int = {
      stringHolder.hashCode()
    }       
  }

  def main(args : Array[String]) : Unit = {
    val l1 = List(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
    val l2 = List(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
    println (l1.diff(l2))
    println (l1.intersect(l2))
    println (l1.union(l2))
  }
}

除了使用合理的
equals
方法将这些值封装到某个对象上之外,您没有太多选择。

除了使用合理的
equals
方法将这些值封装到某个对象上之外,您没有太多选择。

我不太确定:如果实现diff,可能会出现错误?使用不推荐使用的
--
而不是
diff
实际上对我很有用<代码>设置而不是
列表
也起作用

我没有答案(只是建议使用Set作为解决方法),但我在这里添加了自己的测试,以防它们可以帮助其他人获得答案:

// re-implementing JStringHolder in scala
// to show that this is not java-specific
class JStringHolder(val st: String) {
    override def equals(that: Any): Boolean = that match {
        case t: JStringHolder => this.st == t.st
        case _ => false
    }
}
case class Test(stringHolder: JStringHolder) {
    override def equals(that: Any) : Boolean = that match {
        case t: Test => this.stringHolder == t.stringHolder
        case _ => false
    }
}
现在在REPL(scala 2.9.0.1)中:

--已弃用,但有效

scala> res0 -- res1
<console>:13: warning: method -- in class List is deprecated: use `list1 filterN
ot (list2 contains)` instead
       res0 -- res1
            ^
res3: List[Test] = List(a)
另外,显示所有内容都与
Set

scala> Set(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
res0: scala.collection.immutable.Set[Test] = Set(a, b)

scala> Set(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
res1: scala.collection.immutable.Set[Test] = Set(b, c)

scala> res0 diff res1
res2: scala.collection.immutable.Set[Test] = Set(a)

scala> res0 union res1
res3: scala.collection.immutable.Set[Test] = Set(a, b, c)

scala> res0 intersect res1
res4: scala.collection.immutable.Set[Test] = Set(b)

我不是很确定:如果实现diff,可能是一个bug?使用不推荐使用的
--
而不是
diff
实际上对我很有用<代码>设置而不是
列表
也起作用

我没有答案(只是建议使用Set作为解决方法),但我在这里添加了自己的测试,以防它们可以帮助其他人获得答案:

// re-implementing JStringHolder in scala
// to show that this is not java-specific
class JStringHolder(val st: String) {
    override def equals(that: Any): Boolean = that match {
        case t: JStringHolder => this.st == t.st
        case _ => false
    }
}
case class Test(stringHolder: JStringHolder) {
    override def equals(that: Any) : Boolean = that match {
        case t: Test => this.stringHolder == t.stringHolder
        case _ => false
    }
}
现在在REPL(scala 2.9.0.1)中:

--已弃用,但有效

scala> res0 -- res1
<console>:13: warning: method -- in class List is deprecated: use `list1 filterN
ot (list2 contains)` instead
       res0 -- res1
            ^
res3: List[Test] = List(a)
另外,显示所有内容都与
Set

scala> Set(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
res0: scala.collection.immutable.Set[Test] = Set(a, b)

scala> Set(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
res1: scala.collection.immutable.Set[Test] = Set(b, c)

scala> res0 diff res1
res2: scala.collection.immutable.Set[Test] = Set(a)

scala> res0 union res1
res3: scala.collection.immutable.Set[Test] = Set(a, b, c)

scala> res0 intersect res1
res4: scala.collection.immutable.Set[Test] = Set(b)

问题是,您应该以一种方式重写hashCode方法,即两个实例显示相同的hashCode,而您认为它们是相同的。只有当hashCode相同时,才会调用equals方法,否则两个实例不相同(至少在List.diff和intersect的意义上)

使用以下代码将实现我想要的结果:

List(a)
List(b)
List(a, b, b, c)
下面是使用过的代码:

package scalatest;

public class JStringHolder {
String s = null;

public JStringHolder(String newString){
    s = newString;
}

@Override
public String toString() {
    return s;
}

@Override
public boolean equals(Object obj) {
    System.out.println("SHEQ " + this.s + " AND " + ((JStringHolder)obj).s + " " + this.s.equals(((JStringHolder)obj).s));
    return this.s.equals(((JStringHolder)obj).s);
}
}
package scalatest;

public class JStringHolder {
String s = null;

public JStringHolder(String newString){
    s = newString;
}

@Override
public String toString() {
    return s;
}

@Override
public boolean equals(Object obj) {
    return this.s.equals(((JStringHolder)obj).s);
}
@Override
public int hashCode() {
    return s.hashCode();
}
}
以及要执行的scala代码:

package scalatest

object ListTest {

  trait AbstractTest 
  case class Test(stringHolder: scalatest.JStringHolder) extends AbstractTest {
    override def toString = stringHolder.toString()
    override def equals(ot: Any) : Boolean = {
      return stringHolder.equals(ot.asInstanceOf[Test].stringHolder)
    }

  }

  def main(args : Array[String]) : Unit = {
    val l1 = List(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
    val l2 = List(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
    println (l1.diff(l2))
    println (l1.intersect(l2))
    println (l1.union(l2))
  }
}
package scalatest

object ListTest {

  trait AbstractTest 
  case class Test(stringHolder: scalatest.JStringHolder) extends AbstractTest {
    override def toString = stringHolder.toString()
    override def equals(ot: Any) : Boolean = {
      return stringHolder.equals(ot.asInstanceOf[Test].stringHolder)
    }
    override def hashCode() : Int = {
      stringHolder.hashCode()
    }       
  }

  def main(args : Array[String]) : Unit = {
    val l1 = List(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
    val l2 = List(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
    println (l1.diff(l2))
    println (l1.intersect(l2))
    println (l1.union(l2))
  }
}

问题是,您应该以一种方式重写hashCode方法,即两个实例显示相同的hashCode,而您认为它们是相同的。只有当hashCode相同时,才会调用equals方法,否则两个实例不相同(至少在List.diff和intersect的意义上)

使用以下代码将实现我想要的结果:

List(a)
List(b)
List(a, b, b, c)
下面是使用过的代码:

package scalatest;

public class JStringHolder {
String s = null;

public JStringHolder(String newString){
    s = newString;
}

@Override
public String toString() {
    return s;
}

@Override
public boolean equals(Object obj) {
    System.out.println("SHEQ " + this.s + " AND " + ((JStringHolder)obj).s + " " + this.s.equals(((JStringHolder)obj).s));
    return this.s.equals(((JStringHolder)obj).s);
}
}
package scalatest;

public class JStringHolder {
String s = null;

public JStringHolder(String newString){
    s = newString;
}

@Override
public String toString() {
    return s;
}

@Override
public boolean equals(Object obj) {
    return this.s.equals(((JStringHolder)obj).s);
}
@Override
public int hashCode() {
    return s.hashCode();
}
}
以及要执行的scala代码:

package scalatest

object ListTest {

  trait AbstractTest 
  case class Test(stringHolder: scalatest.JStringHolder) extends AbstractTest {
    override def toString = stringHolder.toString()
    override def equals(ot: Any) : Boolean = {
      return stringHolder.equals(ot.asInstanceOf[Test].stringHolder)
    }

  }

  def main(args : Array[String]) : Unit = {
    val l1 = List(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
    val l2 = List(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
    println (l1.diff(l2))
    println (l1.intersect(l2))
    println (l1.union(l2))
  }
}
package scalatest

object ListTest {

  trait AbstractTest 
  case class Test(stringHolder: scalatest.JStringHolder) extends AbstractTest {
    override def toString = stringHolder.toString()
    override def equals(ot: Any) : Boolean = {
      return stringHolder.equals(ot.asInstanceOf[Test].stringHolder)
    }
    override def hashCode() : Int = {
      stringHolder.hashCode()
    }       
  }

  def main(args : Array[String]) : Unit = {
    val l1 = List(Test(new JStringHolder("a")), Test(new JStringHolder("b")))
    val l2 = List(Test(new JStringHolder("b")), Test(new JStringHolder("c")))
    println (l1.diff(l2))
    println (l1.intersect(l2))
    println (l1.union(l2))
  }
}
第一个测试(JStringHolder(“b”)不是==第二个


第一个测试(JStringHolder(“b”)不是==第二个。

经过多次尝试,我认为它是hashCode方法。如果您正确覆盖它。上面的代码可以正常工作。谢谢大家的回答!所有的工作都必须是后台的哈希表。@John:你应该在答案中输入正确的代码,并将其标记为正确的(为将来的其他人)。我仍然认为会发生一些奇怪的事情,因为JStringHolder和Test的等式似乎是有效的(
new-JStringHolder(“a”)==new-JStringHolder(“a”)
是真的,
Test(new-JStringHolder(“a”)==Test(new-JStringHolder(“a”)
是真的…)我想插入它作为答案,但我不允许在提交问题后8小时内回答。我将在以后添加代码。。。您是对的,如果您仅对StringHolder使用“==”它将起作用。问题在于列表的diff和intersect方法。他们似乎使用hashCode来区分实例……经过多次尝试,我认为这就是hashCode方法。如果您正确覆盖它。上面的代码可以正常工作。谢谢大家的回答!所有的工作都必须是后台的哈希表。@John:你应该在答案中输入正确的代码,并将其标记为正确的(为将来的其他人)。我仍然认为会发生一些奇怪的事情,因为JStringHolder和Test的等式似乎是有效的(
new-JStringHolder(“a”)==new-JStringHolder(“a”)
是真的,
Test(new-JStringHolder(“a”)==Test(new-JStringHolder(“a”)
是真的…)我想插入它作为答案,但我不允许在提交问题后8小时内回答。我将在以后添加代码。。。您是对的,如果您仅对StringHolder使用“==”它将起作用。问题在于列表的diff和intersect方法。它们似乎使用hashCode来区分实例……整个问题是您需要重写
hashCode
方法。这真的很愚蠢,但这就是它目前的工作方式。希望scala更新
diff
实现,使其基于
equals
而不是
hashCode
@GeorgePligor。当您更改
equals
时,通常需要覆盖
hashCode
——这不是可选的,而是每个类从
对象继承的
hashCode
API的契约,它在
hashCode
equals
JavaDoc上都有描述。如果你不这样做,你的代码就被破坏了,句号。你所说的可能是正确的,但不管怎样,我认为这都是愚蠢的。我决不会那样设计它。对你没有冒犯,但对那些隐式创建了你需要学习的此类限制的人来说,因为编译器永远不会告诉你。整个问题是你需要重写
hashCode
方法。这真的很愚蠢,但这就是它目前的工作方式。希望scala更新
diff
实现,使其基于
equals
而不是
hashCode
@GeorgePligor。当您更改
equals
时,通常需要覆盖
hashCode
——这不是可选的,而是每个类从
对象继承的
hashCode
API的契约