Scala 如何推广round方法

Scala 如何推广round方法,scala,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, R

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

您可以使用type类

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égis Jean Gilles评论的那样)

使用BigDecimal方法更新了
以清除
round
函数(感谢Régis Jean Gilles)

可与
Double
Long
BigDecimal

round(10, 1)
round(Long.MaxValue - 1000L, -1)
round(BigDecimal("1234"), -2)
您可以使用type类

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égis Jean Gilles评论的那样)

使用BigDecimal
方法更新了
以清除
round
函数(感谢Régis Jean Gilles)

可与
Double
Long
BigDecimal

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

谢谢你的回答,为什么我要把n转换成Double?长型是否会溢出?@YijieShen n不会转换为
Double
,n是类型
T
数值
类型类的一个实例,该类型将
输入
转换为
Double
。然后使用
Double
创建一个
BigDecimal
。不过,转换为Double是一个合理的问题。如果
input
本身是一个
bigdecimic
(或任何不能安全转换为
Double
)怎么办?现在OP的代码片段确实没有这种情况,但即使对于
Long
——就像OP的代码中的第四个重载一样——它也是不安全的(不是所有
Long
s都可以放在一个双精度中)。@RégisJean Gilles你是对的。我已经将我的答案更新为处理
Long
,但它仍然不适用于具有
Numeric
类型类(如
bigdecime
)的其他类型。您使用
tobigdecime
进行的更新可能就是我应该做的。尽管考虑到整个代码比原始代码大,它很容易显得毫无意义,但其优点是
ToBigDecimal
类型类是一种通用粘合剂,可以在其他上下文中随意重用。在这里,您甚至可以添加一个
fromBigDecimal
方法,允许完全不需要显式的
f
参数(然后只需执行
round(10,1)
而不是
round(10,1,uuu.toInt)
),谢谢您的回答,为什么我应该将n转换为Double?长型是否会溢出?@YijieShen n不会转换为
Double
,n是类型
T
数值
类型类的一个实例,该类型将
输入
转换为
Double
。然后使用
Double
创建一个
BigDecimal
。不过,转换为Double是一个合理的问题。如果
input
本身是一个
bigdecimic
(或任何不能安全转换为
Double
)怎么办?现在OP的代码片段确实没有这种情况,但即使对于
Long
——就像OP的代码中的第四个重载一样——它也是不安全的(不是所有
Long
s都可以放在一个双精度中)。@RégisJean Gilles你是对的。我已经将我的答案更新为处理
Long
,但它仍然不适用于具有
Numeric
类型类(如
bigdecime
)的其他类型。您使用
tobigdecime
进行的更新可能就是我应该做的。尽管考虑到整个代码比原始代码大,它很容易显得毫无意义,但其优点是
ToBigDecimal
类型类是一种通用粘合剂,可以在其他上下文中随意重用。当您使用它时,您甚至可以添加一个
fromBigDecimal
方法,允许完全不需要显式的
f
参数(然后只需执行
round(10,1)
而不是
round(10,1,uuu.toInt)