【发布时间】:2014-11-21 03:22:57
【问题描述】:
注意:请耐心等待,我不是在问如何覆盖 equals 或如何创建自定义方法来比较浮点值。
Scala 在允许按值比较对象方面非常出色,并提供了一系列工具来用很少的代码来实现这一点。特别是案例类、元组和允许比较整个集合。
我经常调用进行密集计算并生成要返回的重要数据结构的方法,然后我可以编写一个单元测试,在给定特定输入的情况下将调用该方法,然后将结果与硬编码值进行比较。例如:
def compute() =
{
// do a lot of computations here to produce the set below...
Set(('a', 1), ('b', 3))
}
val A = compute()
val equal = A == Set(('a', 1), ('b', 3))
// equal = true
这是一个简单的示例,我在这里省略了来自特定测试库等的任何代码。 鉴于浮点值不能可靠地与 equals 进行比较,以下相当等价的示例会失败:
def compute() =
{
// do a lot of computations here to produce the set below...
Set(('a', 1.0/3.0), ('b', 3.1))
}
val A = compute()
val equal2 = A == Set(('a', 0.33333), ('b', 3.1)) // Use some arbitrary precision here
// equal2 = false
我想要的是有一种方法可以在该调用中进行所有浮点比较,以使用任意级别的精度。但请注意,我不控制(或想以任何方式改变)Set 或 Double。
我尝试定义从 double 到新类的隐式转换,然后重载该类以返回 true。然后我可以在我的硬编码验证中使用该类的实例。
implicit class DoubleAprox(d: Double)
{
override def hashCode = d.hashCode()
override def equals(other : Any) : Boolean = other match {
case that : Double => (d - that).abs < 1e-5
case _ => false
}
}
val equals3 = DoubleAprox(1.0/3.0) == 0.33333 // true
val equals4 = 1.33333 == DoubleAprox(1.0/3.0) // false
但正如您所见,它破坏了对称性。鉴于我正在比较更复杂的数据结构(集合、元组、案例类),如果equals() 将在左侧或右侧调用,我无法先验地定义。似乎我必须遍历所有结构,然后在分支上进行单浮点比较......所以,问题是:有没有办法做到这一点??
附带说明:我很好地阅读了entire chapter on object equality 和几个博客,但它们只提供了继承问题的解决方案,并且要求您基本上拥有所有涉及的类并更改所有这些类。考虑到它试图解决的问题,所有这些似乎都相当复杂。
在我看来,平等是 Java 中根本被破坏的事情之一,因为必须将方法添加到每个类并一次又一次地永久覆盖。对我来说更直观的是拥有编译器可以找到的比较方法。比如说,您将提供 equals(DoubleAprox, Double) 并且每次您想比较这些类的 2 个对象时都会使用它。
【问题讨论】:
标签: scala