我是scala的新手,并试图了解正确的思考子类型的方法,所以这是一个简单的例子。
让我们说我想创建一个函数truncation()
,它取一个数字并将其舍入到几个小数位并返回结果。我可能会这样做,
def truncation(number:Double, level:Int)={
math.floor(number * math.pow(10,level)) / math.pow(10,level)
}
truncation(1.2345, 2)
res0: Double = 1.23
但我可能还希望此函数与Double
之外的其他数字类型一起使用,例如Float
。
那么我应该如何考虑推广这个函数以适应多种类型呢?
我认为我应该使用泛型类型,例如
def truncation [A](number:A, level:Int):A={
math.floor(number * math.pow(10,level)) / math.pow(10,level)
}
但这并没有编译。
如果只有两种类型,我会看到Either
类型is a good option。但是在更一般的情况下,也许我也希望能够处理Ints
,并且在输入对象的类型上具有match
的不同实现。
考虑这个问题的最佳方法是什么?谢谢你的帮助。
答案 0 :(得分:3)
对于要约束为数字类型的通用,可以使用Numeric
:
def truncation[T](number: T, level:Int)(implicit n: Numeric[T]) = {
import math._
val doubleValue = n.toDouble(number)
floor(doubleValue * pow(10,level)) / pow(10,level)
}
或等效地:
def truncation[T : Numeric](number: T, level:Int) = {
import math._
val doubleValue = implicitly[Numeric[T]].toDouble(number)
floor(doubleValue * pow(10,level)) / pow(10,level)
}
这些适用于Ints
,Doubles
,Floats
和其他数字类型。
第一个示例使用隐式参数,您可以阅读here。第二个版本使用上下文绑定,您可以与implicitly
运算符一起阅读here运算符,您可以阅读here。最后,阅读Numeric
here的文档以查看所有可用的方法。
请注意,上述版本都返回Double
。如果您希望它们返回T
(无论输入类型是什么),您可以尝试:
def truncation[T : Numeric](number: T, level:Int): T = implicitly[Numeric[T]] match {
case n:Fractional[T] =>
val tenPow = n.fromInt(math.pow(10, level).toInt)
n.div(n.fromInt(n.toInt(n.times(number, tenPow))), tenPow)
case n:Integral[T] => number
}