2015-06-22 50 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」都適合雙精度)。 –