I am looking for a Generic functional way to convert between Scala String to any numeric type. I need in case of failure to pass a default value.
For example, I need to convert from String
to Int
but in case the String to Int conversion failed. I need to pass a default value without having throws java.lang.NumberFormatException
. I tried this way but doesn't get my idea as I need it generic and also with default value in case of exception
Edit: I updated the solution to parse from any type to any type. This makes the solution more generic based on the question requested. I think you can use Scala functional way to have the generic type [T]
but you need to split it into two parts.
First to implement parse types which parses from any type [U]
to
any type [T]
. parseTypes
takes a function canBuildFrom
as a parameter using Scala functional way. Then based on the output of this function you will checks if it parsed correctly or it has an exception. Also, in case it failed to parse you can pass a default parameter.
def parseTypes[T,U](str: U, canBuildFrom: U ⇒ T): Either[java.lang.NumberFormatException, T] =
Try(canBuildFrom(str)).map(Right(_)).getOrElse {
Left(new java.lang.NumberFormatException(str.toString))
}
def safeParse[T,U](attributeValue: U, canBuildFrom: U ⇒ T, defaultValue: T): T = {
parseTypes(attributeValue, canBuildFrom) match {
case Right(x) ⇒ x
case Left(x) ⇒ defaultValue
case _ ⇒ defaultValue
}
}
def safeParseDoubleToBigDecimal(attributeValue: Double): BigDecimal = safeParse[BigDecimal,Double](attributeValue, toBigDecimal, 0.0)
You can use it to parse String to Int, Double, and Decimal as following:
def safeParseStringToInt(attributeValue: String): Int = safeParse[Int,String](attributeValue, _.toInt, 0)
def safeParseStringToDouble(attributeValue: String): Double = safeParse[Double ,String](attributeValue, _.toDouble, 0.0)
def safeParseStringToBigDecimal(attributeValue: String): BigDecimal = safeParse[BigDecimal ,String](attributeValue, BigDecimal(_), 0.0)
// example of usage
val x:Int = safeParseStringToInt("123",0)
val y:Int = safeParseStringToInt("aaa",0)
Update: I update this answer as I realized that @Dima's answer is somehow more functional and better than my answer I added the answer below copied from @Dima's answer as my answer marked as the correct answer.
trait ParseIt[T] {
protected def parse(s: String): T
def apply(s: String) = Try(parse(s)).toOption
}
implicit object ParseInt extends ParseIt[Int] {
protected def parse(s: String) = s.toInt
}
implicit object ParseDouble extends ParseIt[Double] {
protected def parse(s: String) = s.toDouble
}
// etc ...
def parse[T : ParseIt](s: String, orElse: => T) =
implicitly[ParseIt[T]](s).getOrElse(orElse)
val n: Int = parse("123", 0)
val d: Double = parse("123", 0.0)
This sort of thing is implemented really nice with typeclasses:
trait ParseIt[T] {
protected def parse(s: String): T
def apply(s: String) = Try(parse(s)).toOption
}
implicit object ParseInt extends ParseIt[Int] {
protected def parse(s: String) = s.toInt
}
implicit object ParseDouble extends ParseIt[Double] {
protected def parse(s: String) = s.toDouble
}
// etc ...
def parse[T : ParseIt](s: String, orElse: => T) =
implicitly[ParseIt[T]](s).getOrElse(orElse)
val n: Int = parse("123", 0)
val d: Double = parse("123", 0.0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With