Scala 如何推广round方法
我有以下四种方法,使用BigDecimal对数字进行四舍五入: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
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)
)