I would like to introduce a custom class, say Decimal2
, so that I would be able to round through type ascription:
val x: Decimal2 = 1.2345
// 1.24
So far I've tried this:
class Decimal2(val value: Double)
object Decimal2 {
def apply(value: Double) =
BigDecimal(value).
setScale(2, BigDecimal.RoundingMode.HALF_UP).
toDouble
implicit def doubleToDecimal2(x: Double) = Decimal2(x)
}
val a: Decimal2 = 1.2345
But:
- the last line apparently fails.
- return type of apply method is
Double
, notDecimal2
How can I reach my goal?
CodePudding user response:
It looks like you have two requirements.
- Make Decimal2 class provides a method that returns a rounded
Double
value. - Convert Double value to Decimal2 class
Here is a straightforward approach.
case class Decimal2(value: Double){
def toDouble: Double = BigDecimal(value).
setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
}
implicit class DoubleImprovement(val x: Double){
def toDecimal2: Decimal2 = Decimal2(x)
}
println(1.2345.toDecimal2.toDouble)
CodePudding user response:
It's easy to do this with scala 3 opaque type. I would say even more, opaque type is made for this kind of thing.
// a Decimal2 is a Double with some restriction
opaque type Decimal2 = Double
object Decimal2 :
def apply(d2 : Double) : Decimal2 = BigDecimal(d2).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
// extension method to Decimal2 to have a back conversion to a full Double
extension (d2 : Decimal2)
def double : Double = d2
// implicit conversion for convenience
given doubleToDecimal2 : Conversion[Double, Decimal2] = Decimal2(_)
now you can use it like you want :
val d2 : Decimal2 = 1.23456 // 1.23
d2 // Decimal2
d2.double // double
CodePudding user response:
One way is by explicitly creating a new instance of Decimal2
from apply
method.
object Decimal2 {
def apply(value: Double): Decimal2 =
new Decimal2(BigDecimal(value)
.setScale(2, BigDecimal.RoundingMode.HALF_UP)
.toDouble)
implicit def doubleToDecimal2(x: Double): Decimal2 = Decimal2(x)
}
Another option is to tag the type:
trait RoundTo2
type Decimal2 = Double with RoundTo2
object Decimal2 {
def apply(value: Double): Decimal2 = {
BigDecimal(value)
.setScale(2, BigDecimal.RoundingMode.HALF_UP)
.toDouble
}.asInstanceOf[Double with RoundTo2]
}
implicit def doubleToDecimal2(x: Double): Decimal2 = Decimal2(x)
val a: Decimal2 = 1.2345