2015-06-22 33 views
0

我有以下四种方法,使用的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,我该怎么办?

回答

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) 
+0

谢谢您的回答,我为什么要转换N到翻番?会不会Long型溢出? –

+0

@YijieShen n未转换为“Double”,n是''T'类型的'Numeric'类的实例,它将'input'转换为'Double'。然后'Double'用于创建'BigDecimal'。 –

+3

虽然转换为double是一个合理的问题。如果'input'本身是一个'BigDecimal'(或者任何不能安全转换为'Double'的东西)?现在确实,OP的代码片段没有这种情况,但即使对于“Long” - 就像OP代码中的第4次重载一样 - 这是不安全的(并非所有的“Long”都适合双精度)。 –