Scala:检查对象是否为数字

14

能否通过模式匹配来检测某个东西是否是Numeric?我想要实现以下操作:

class DoubleWrapper(value: Double) {
  override def equals(o: Any): Boolean = o match {
    case o: Numeric => value == o.toDouble
    case _ => false
  }
  override def hashCode(): Int = value ##
}

当然,这并不起作用,因为Numeric不是像IntDouble这样的东西的超类型,它是一个类型类(typeclass)。我也不能像def equals[N: Numeric](o: N)那样做,因为o必须是Any才能符合equals的约定。

那么,如果我不想列出每个已知的Numeric类(包括用户定义的类,我甚至可能不知道它们),我该怎么办?


问题无法解决,正如下面的答案所指出的那样,但你可以通过一些hack方法来解决(例如将其转换为字符串并解析为double)。像大多数hack一样,这种方法不太好,但可能有效。另一个hack方法可能是对该值进行正则表达式匹配...但是,实际上,在上述情况中,您是否需要担心任何不是Double的内容呢?调用代码不能遵循某种约定吗?调用代码真的需要所有不同类型的数字表示吗?为什么要重新定义Double的equals方法?这是值得思考的问题... - aishwarya
2个回答

5
原始问题是不可解决的,以下是我的推理:
要确定一个类型是否是类型类(如 Numeric)的实例,我们需要隐式解析。隐式解析是在编译时完成的,但我们需要它在运行时完成。目前这是不可能的,因为据我所知,Scala 编译器没有在已编译的类文件中留下所有必要的信息。为了证明这一点,可以编写一个测试类,其中包含一个带有 implicit 修饰符的局部变量的方法。当移除修饰符后,编译输出不会发生变化。

这不是真的,scalac会存储信息以判断某些内容是否为implicit:https://github.com/scala/scala/blob/master/src/reflect/scala/reflect/api/Symbols.scala#L239 - kiritsuku
1
比起运行时信息是否可用,更重要的是隐式解析是一个作用域问题,例如导入符号。这在运行时根本无法有意义地完成。结果是一样的:这个“问题”是无法解决的。对于你想要检查的一组类型(例如原始类型),它是可以解决的。否则,您需要设计一个接口来“注册”可比较的类型。 - 0__
我完全同意,有很多原因为什么它不会起作用。 - Kim Stebel

0
你是否正在使用DoubleWrapper来为Double添加方法?那么它应该是一个透明类型,即你不应该保留实例,而是定义扩展的方法返回Double。这样你就可以继续使用原始类型定义的==,它已经做到了你想要的效果(6.0 == 6返回true)。

好的,如果不行,那怎么样?

override def equals(o: Any): Boolean = o == value

如果您相应地构建其他包装器的equals方法,您应该最终再次比较原始值。
另一个问题是,对于有状态的包装器,您是否应该拥有这样的equals方法。我认为可变对象不应根据它们持有的一个值而相等 - 您很可能会遇到麻烦。

不,我不是。我的实际类确实存储状态,而不仅仅是向Double添加方法。 - dhg
我喜欢你的建议,因为它避免了问题(尽管我仍然好奇原始问题是否可解决)。我同意关于等式方法的设计(因为它不会对称),但我没问题。 - dhg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接