scala正确子类型的简单示例

时间:2015-04-02 14:16:55

标签: scala

我是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的不同实现。

考虑这个问题的最佳方法是什么?谢谢你的帮助。

1 个答案:

答案 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)
}

这些适用于IntsDoublesFloats和其他数字类型。

第一个示例使用隐式参数,您可以阅读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
}