啊,浮点数的乐趣。
我认为用模糊比较覆盖等于不是一个好主意。它违反了你通常认为平等的各种事情。想象 a、b 和 c 是一些具有模糊等式的案例类。那么可能有 a, b, c 使得 a==b, b==c 但 a!=c。
然后是哈希码的行为需要考虑。如果你用模糊相等覆盖equals并且不覆盖hashcode,你将不能在hashmap或set中使用结果对象,因为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)
请注意,隐式不是类的参数,而是操作的参数。