等于具有浮点字段的案例类

Ble*_*ezz 3 scala hashcode case-class

是否可以,使用浮点字段创建案例类,如:

case class SomeClass(a:Double, b:Double) 
Run Code Online (Sandbox Code Playgroud)

我想自动生成的相等方法在这种情况下不起作用.压倒等于最佳解决方案?

编辑:

如果重写等于是要走的路,我想避免硬编码epsilon(其中epsilon被定义为=> | this.aa | <epsilon).这不会编译:

case class SomeClass(a:Double, b:Double, implicit epsilon:Double)  
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种方法来传递epsilon,而不是每次都传递音乐会价值(一些"隐含的"魔法).

我还跟进了更一般的问题,你如何定义只有浮点字段的类的哈希码?

dby*_*rne 5

你是对的.如果你担心精度,那么你需要覆盖equals:

case class SomeClass(a:Double, b:Double)
SomeClass(2.2 * 3, 1.0) == SomeClass(6.6, 1.0)
// res0: Boolean = false

case class BetterClass(a: Double, b: Double) {
  override def equals(obj: Any) = obj match {
    case x: BetterClass =>
      (this.a - x.a).abs < 0.0001 && (this.b - x.b).abs < 0.0001   
    case _ => false
  }
}
BetterClass(2.2 * 3, 1.0) == BetterClass(6.6, 1.0)
// res1: Boolean = true
Run Code Online (Sandbox Code Playgroud)


Rüd*_*ehn 5

啊,浮点数的喜悦。

我认为用模糊比较来覆盖相等不是一个好主意。它违反了您通常认为是平等的一切事情。想象一下,a,b和c是一些带有模糊等式的案例类。这样就有可能使a,b,c成为a == b,b == c但a!= c。

然后是要考虑的哈希码的行为。如果用模糊等式覆盖等号并且不覆盖哈希码,则将无法在哈希图或集合中使用结果对象,因为a == b而是a.hashcode!= b.hashcode。

解决问题的最佳方法是定义一个运算符,例如=〜=,它除了提供equals / ==之外还提供模糊比较(至少对于scala中的不可变对象而言),这意味着对象是完全相同的,因此您可以替换一个而不更改计算结果。

如果您还希望能够通过隐式配置比较的精度,那么会增加另一级别的复杂性。这是一个更完整的示例:

// a class to configure the comparison that will be passed to the operator 
// as an implicit value
case class CompareSettings(epsilon:Double = 0.1) extends AnyVal

// add an operator =~= to double to do a fuzzy comparions
implicit class DoubleCompareExtensions(val value:Double) extends AnyVal {
  def =~=(that:Double)(implicit settings:CompareSettings) : Boolean = {
    // this is not a good way to do a fuzzy comparison. You should have both relative
    // and absolute precision. But for an example like this it should suffice.
    (value - that).abs < settings.epsilon
  }
}

case class SomeClass(x:Double, y:Double) {
  // we need an implicit argument of type CompareSettings
  def =~=(that:SomeClass)(implicit settings:CompareSettings) =
    // the implicit argument will be automatically passed on to the operators
    this.x =~= that.x && this.y =~= that.y
}

// usage example
val x=1.0
val y=1.01

// this won't work since there is no implicit in scope
x =~= y

// define an implicit of the right type
implicit val compareSettings = CompareSettings(0.2)

// now this will work
x =~= y

// and this as well
SomeClass(1,2) =~= SomeClass(1.1,2)
Run Code Online (Sandbox Code Playgroud)

注意,隐式不是类的参数,而是操作的参数。