Reputation: 750
I was trying to create an array containing all Int
, Long
and Double
types. However, I found that the Long
and Int
types are automatically converted to Double
.
Here's a minimal example,
object HelloWorld {
def main(args: Array[String]): Unit = {
val types = Array[Byte]('i', 'l', 'd', 'd')
val array = Array[String]("1", "2000000", "20.0", "2020.0")
val values = array.zip(types) map { case (s, t) =>
t match {
case 'i' => s.toInt
case 'l' => s.toLong
case 'd' => s.toDouble
}
}
values.foreach { println }
}
}
The result is
1.0
2000000.0
20.0
2020.0
How can I avoid such conversion? Thanks.
Upvotes: 2
Views: 397
Reputation: 34423
This is because the compiler tries to come with a least surprising type of the match
expresion, which is a type all those types (Int
, Long
and Double
) can be converted to:
t match {
case 'i' => s.toInt
case 'l' => s.toLong
case 'd' => s.toDouble
}
You can use a type ascription or an assignment to provide your own type instead, which may be Numeric
or AnyVal
.
case (s, t) => (t match {
case 'i' => s.toInt
case 'l' => s.toLong
case 'd' => s.toDouble
}):AnyVal
or
val result: AnyVal = t match {
case 'i' => s.toInt
case 'l' => s.toLong
case 'd' => s.toDouble
}
result
Another alternative is to use the :AnyVal
type ascription on any of the case results, which will also make the compiler to give up trying coming up with a more sensible type:
t match {
case 'i' => s.toInt:AnyVal
case 'l' => s.toLong
case 'd' => s.toDouble
}
Upvotes: 2
Reputation: 48430
The expression
t match {
case 'i' => s.toInt
case 'l' => s.toLong
case 'd' => s.toDouble
}
infers to Double
because Scala 2 calculates weak least upper bound. One option is to use type ascription to tell the compiler explicitly the regular least upper bound, for example,
(t match {
case 'i' => s.toInt
case 'l' => s.toLong
case 'd' => s.toDouble
}): AnyVal
Scala 3 drops the notion of weak conformance
drops the general notion of weak conformance, and instead keeps one rule: Int literals are adapted to other numeric types if necessary.
so your example would work as intended.
Upvotes: 3
Reputation: 1025
This is not the cleverest way: make a list of lists, then flatten.
val types = List[Byte]('i', 'l', 'd', 'd')
val array = List[String]("1", "2000000", "20.0", "2020.0")
val values = array.zip(types) map {
case (s, t) => t match {
case 'i' => List(s.toInt)
case 'l' => List(s.toLong)
case 'd' => List(s.toDouble)
}
}
values.flatten
Here's the Scastie snippet: https://scastie.scala-lang.org/tpLbvlg1TrKmQsqeZRsDTg
P.S. Arrays are provided in Scala mostly for the sake of Java interoperability. Otherwise prefer lists.
Upvotes: 0