如何概括圆方法

时间:2015-06-22 11:29:42

标签: scala

我有以下四种方法,使用BigDecimal来舍入数字:

private def round(input: Byte, scale: Int): Byte = {
  BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).byteValue()
}

private def round(input: Short, scale: Int): Short = {
  BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).shortValue()
}

private def round(input: Int, scale: Int): Int = {
  BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).intValue()
}

private def round(input: Long, scale: Int): Long = {
  BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).longValue()
}

并计划将其概括为一轮:

private def round[T](input: Any, scale: Int, f: (BigDecimal) => T): T = {
  f(BigDecimal(input.asInstanceOf[T]).setScale(scale, RoundingMode.HALF_UP))
}

并像这样使用这一轮:

round[Byte](b, scale, _.byteValue)
round[Short](s, scale, _.shortValue)

但上述广义round无效,因为BigDecimal.apply无法应用于T,我该怎么办?

1 个答案:

答案 0 :(得分:5)

您可以使用Numeric类型

def round[T](input: T, scale: Int, f: BigDecimal => T)(implicit n: Numeric[T]): T = { 
   f(BigDecimal(n.toDouble(input)).setScale(scale, RoundingMode.HALF_UP)) 
}

可以用作:

round(5.525, 2, _.doubleValue)
res0: Double = 5.53

round(123456789L, -5, _.longValue)
res1: Long = 123500000

另一种方法可能是创建一个BigDecimalConverter类型的类,这不是简洁但解决了转换为Double 的问题(这不是一个好主意一个通用函数,如RégisJean-Gilles在下面评论过。)

使用fromBigDecimal方法更新以清理round功能(感谢RégisJean-Gilles)。

trait BigDecimalConverter[T] {
  def toBigDecimal(in: T) : BigDecimal
  def fromBigDecimal(bd: BigDecimal) : T
}

object BigDecimalConverter {
  implicit object IntToBigDecimal extends BigDecimalConverter[Int] {
    def toBigDecimal(in: Int) = BigDecimal(in)
    def fromBigDecimal(bd: BigDecimal) = bd.toInt
  }

  implicit object DoubleToBigDecimal extends BigDecimalConverter[Double] {
    def toBigDecimal(in: Double) = BigDecimal(in)
    def fromBigDecimal(bd: BigDecimal) = bd.toDouble
  }

  implicit object LongToBigDecimal extends BigDecimalConverter[Long] {
    def toBigDecimal(in: Long) = BigDecimal(in)
    def fromBigDecimal(bd: BigDecimal) = bd.toLong
  }

  implicit object BigDecimalToBigDecimal extends BigDecimalConverter[BigDecimal] {
    def toBigDecimal(in: BigDecimal) = in
    def fromBigDecimal(bd: BigDecimal) = bd
  }
}

def round[T](input: T, scale: Int)(implicit bdc: BigDecimalConverter[T]): T = 
   bdc.fromBigDecimal(
     bdc.toBigDecimal(input).setScale(scale, BigDecimal.RoundingMode.HALF_UP)
   )

哪些可以与DoubleLongBigDecimal,...正确使用:

round(10, 1)
round(Long.MaxValue - 1000L, -1)
round(BigDecimal("1234"), -2)